`
kidfang
  • 浏览: 15881 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

手工实现JDBC事务管理

阅读更多

事务是不能嵌套的.只能将操作写到一个方法里.以下是单库.

 

手工实现JDBC事务管理

來源:http://www.ublog.cn/user1/11/index.html
By: foxty

最近由于项目原因,底层数据库访问都必须使用JDBC来操作,为了能更好的实现事务,而且也便于将来移植到Ibatis上去,在作设计的时候参照Ibatis的Dao模式来设计dao,然后事务控制就必须得自己手工来实现了。并且一起也实现了事务得嵌套。主要依靠2个类来实现。

1,TransactionUtil类,负责开启事务,提交事务以及关闭事务。
2,Transaction类,用来记录当前事务得状态以及数据库连接。

 

TransactionUtil类
package com.orizone.oa.extra.service;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import net.orizone.oa.common.ConnectionPoolBean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.orizone.comm.util.BusinessException;

public class TransactionUtil 
{
 private final static ThreadLocal local = new ThreadLocal();
 private static Log log = LogFactory.getLog(TransactionUtil.class);
 
 /**
  * 开启事务
  */
 public static void startTransaction()throws  BusinessException
 {
  Transaction tran = (Transaction)local.get();
  //判断此事务是否属于一个顶层事务。
  if(tran == null)
  {
   tran = new Transaction();
   //设置本地线程的connection
   Connection con = ConnectionPoolBean.getConnection();
   try
   {
    con.setAutoCommit(false);
   }catch(SQLException e)
   {
    e.printStackTrace();
    throw new BusinessException(e, "开启事务失败!");
   }
   tran.setConnection(con);
   tran.setCommitCount(0);
   tran.setTransCount(1);
   tran.setTransDeep(1);
   
   local.set(tran);
  }else
  {
   //事务已经开启,将嵌套层次深度加一,将事务次数加一
   tran.setTransCount(tran.getTransCount() + 1);
   tran.setTransDeep(tran.getTransDeep() + 1);
  }  
 }
 
 /**
  * 提交事务
  *
  */
 public static void commitTransaction()throws  BusinessException
 {
  Transaction tran = (Transaction)local.get();
  //如果事务属于嵌套,则不提交数据,直接将层次数减一。
  if(tran.getTransDeep() > 1)
  {
   tran.setTransDeep(tran.getTransDeep() - 1);
   tran.setCommitCount(tran.getCommitCount() + 1);
   return;
  }
  
  Connection con = tran.getConnection();
  try
  {
   if(tran.hasFullExecute())
   {
    con.commit();   
   }
  }catch(SQLException e)
  {
   log.error(e);   
   throw new BusinessException(e, "提交事务失败!");
  }
 }
 
 /**
  * 结束事务
  *
  */
 public static void endTransaction()throws  BusinessException
 {
  Transaction tran = (Transaction)local.get();
  //如果事务属于嵌套,则不关闭连接,直接将层次数减一。
  if(tran.getTransDeep() > 1)
  {
   tran.setTransDeep(tran.getTransDeep() - 1);
   return;
  }
  
  //当前事务已经结束,清空ThreadLocal变量,防止下一次操作拿到已经关闭的Connection对象。
  local.set(null);
  Connection con = tran.getConnection();
  try
  {
   if(!tran.hasFullExecute())
   {
    con.rollback();
   }
  }catch(SQLException e)
  {
   log.error(e);
   throw new BusinessException(e, "事务回滚失败!");
  }finally
  {
   try
   {
    con.close();
   }catch(SQLException se)
   {
    log.error(se);
    throw new BusinessException(se, "关闭事务失败!");
   }
  }
  
 }
 
 /**
  * 获取当前事务的数据库连接。
  * @return
  */
 public static Connection getConnection()
 {
  Transaction tran = (Transaction)local.get();
  Connection  con = tran.getConnection();
  if(con == null)
  {
   con = ConnectionPoolBean.getConnection();   
  }
  return con;
 }
 
 /**
  * 测试代码
  * @param args
  * @throws Exception
  */
 public static void main(String args[])throws Exception
 {
  test();
  test();
 }
 
 /**
  * 测试代码
  *
  */
 private static void test()
 {
  TransactionUtil.startTransaction();
  try
  {
   Connection con = TransactionUtil.getConnection();
   Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
   stmt.executeUpdate("INSERT INTO bb(bb) values('bb')");
   stmt.executeUpdate("INSERT INTO aa(aa) values('aa')");
   //if(true) throw new Exception("");
   TransactionUtil.commitTransaction();
  }catch(Exception e)
  {
   e.printStackTrace();
   //throw new BusinessException("");
  }finally
  {
   TransactionUtil.endTransaction();
  }
 }
}

 

Transaction类

package com.orizone.oa.extra.service;

import java.sql.Connection;

public class Transaction 
{
 //数据库连接对象
 private Connection connection;
 //事务次数
 private int transCount;
 //提交次数
 private int commitCount;
 //事务嵌套层次
 private int transDeep;

 int getCommitCount() 
 {
  return commitCount;
 }

 void setCommitCount(int commitCount) 
 {
  this.commitCount = commitCount;
 }

 Connection getConnection() 
 {
  return connection;
 }

 void setConnection(Connection conn) 
 {
  this.connection = conn;
 }

 public int getTransCount() 
 {
  return transCount;
 }

 void setTransCount(int transCount) 
 {
  this.transCount = transCount;
 }

 int getTransDeep() 
 {
  return transDeep;
 }

 void setTransDeep(int transDeep)
 {
  this.transDeep = transDeep;
 }
 
 /**
  * 判断事务是否完全提交。
  * 通过提交次数和事务次数来判断事务是否完全提交。
  * @return
  */
 boolean hasFullExecute()
 {
  return commitCount + 1 == transCount;
 }
}

代码中出现的ConnectionPoolBean是用来负责获取数据库连接的类。整个思想就是,将一个Transaction相关信息(数据库连接对象,事务次数,提交次数以及事务深度)放入到当前线程的ThradLocal当中,后面的操作都是基于这个事务基础的,这样才能保证事务的原子性。在commit的时候会判断当前事务层次深度,如果为顶层,并且提交次数+1等于事务次数(说明事务是安全完整的执行了),才真正提交到数据库。如果不完整,则在endTrnasaction的时候会回滚整个事务。

虽然这样能够实现事务操作,但是无法实现跨数据库操作,要实现跨数据库的事务估计只能用JTA了。

 

分享到:
评论
1 楼 highill 2010-04-09  
[/i][/b][b][/b][b][/b][b][/b][b][/b][b][/b][b][b][/b][i][/i][i][/i][i][/i][i][/i][i][i][/i]
引用
[img][/img][url][/url][flash=200,200][/flash]

相关推荐

    JdbcTemplate的事务控制.docx

    当使用`JdbcTemplate`结合Spring框架时,可以采用与原生JDBC事务控制类似的方法,但在Spring环境中进行管理。以下是一个使用Druid数据库连接池的示例代码: ```java @RequestMapping("/druidData1") public String ...

    基于JSP毕业设计-+SQL房屋租赁管理信息系统JDBC(源代码+论文+答辩PPT).zip

    一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...

    JSP+SQL房屋租赁管理信息系统JDBC(源代码+论文+答辩PPT).rar

    一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...

    JSP+SQL房屋租赁管理信息系统JDBC(源代码+lw+答辩PPT).zip

    一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...

    JSP+SQL房屋租赁管理信息系统JDBC(源代码+论文+答辩PPT).zip

    一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...

    sqlserver与java连接接操作

    JDBC Connection 接口(java.sql.Connection)提供了两种事务模式:自动提交和手工提交。java.sql.Connection 提供了以下控制事务的方法: * public void setAutoCommit(boolean):设置自动提交模式 * public ...

    基于JAVA JSP+SQL房屋租赁管理信息系统JDBC的毕业设计,以软件工程理论作为系统开发的理论基础,以客户机/服务器模式的

    一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...

    商品库存管理系统(论文).docx

    随着计算机网络技术的快速发展,传统的手工方式进行商品库存管理已经无法满足现代商业运营的需求。本文主要探讨了如何构建一个基于B/S架构的商品库存管理系统,旨在提高管理效率,减轻劳动强度,并提升企业的形象。...

    图书馆管理系统(Java) 优秀毕业设计论文+软件设计源码.zip

    本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。 本系统使有jsp进行网页界面的设计,使用MVC设计模式,...

    SSM学生信息管理系统答辩PPT.pptx

    Spring框架则作为整个系统的中枢,利用控制反转(IoC)和面向切面编程(AOP)理念,实现了依赖注入,使得组件间的耦合度降低,同时也简化了事务管理和安全控制。MyBatis作为持久层框架,直接与数据库交互,提供灵活...

    基于WEB的小区物业管理系统设计与实现样本.doc

    传统的手工管理方式已无法满足需求,因此需要借助信息化工具进行管理。 - **技术背景**:计算机科学技术的进步,特别是Web技术的普及,使得通过网络实现远程访问和管理成为可能。 - **需求背景**:物业管理系统...

    利用JAVA实现图书管理系统毕业论文(20210808203615).pdf

    传统图书馆书籍管理依然停留在手工管理状态,这与技术发展的现状不相符,因此迫切需要为图书馆管理设置一个安全、快速的系统。该系统旨在利用软件开发技术方便快捷地管理书籍,并解决图书馆管理中面临的问题,比如...

    Java数据库手工和execl导入操作

    在这个Java程序中,我们看到了一个巧妙地结合了手工录入和Excel导入功能的实现,这在数据输入和管理领域具有很高的实用性。下面将详细介绍这个程序的核心知识点。 首先,让我们关注Java语言在数据库操作中的应用。...

    人力资源管理系统java前台和sql后台数据库

    在信息化时代,企业的人力资源管理已经从传统的手工操作转变为数字化管理。本文将深入探讨一款基于Java技术的前台系统与SQL Server 2000作为后台数据库的人力资源管理系统。这种组合为企业提供了高效、准确且易于...

    数据库课程设计,学生管理系统,sql

    传统的手工管理方式效率低且易出错,引入数据库管理系统可以大大提高数据处理的效率和准确性。学生管理系统利用SQL数据库,能够实现数据的快速查询、更新和维护,减轻管理工作负担。 1.2 课程设计目的 通过本次课程...

    基于Jsp的图书馆管理系统毕业论文(源码+数据库+sql+word毕业论文文档).zip

    本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。 本系统使有jsp进行网页界面的设计,使用MVC设计模式,...

    学生课程选择管理系统

    本系统旨在优化传统的手工选课流程,提高教学管理效率,同时也提升了学生的选课体验。 一、JSP(JavaServer Pages) JSP是Java平台上的动态网页技术,它允许开发人员将静态HTML内容与动态Java代码结合起来。在本...

    【ssm项目源码】停车场管理系统.zip

    它提供了AOP(面向切面编程)支持,用于日志记录、事务管理等通用任务,以及对JDBC的封装,简化数据库操作。 2. **SpringMVC**:SpringMVC是Spring框架的一个模块,用于处理HTTP请求和响应。它定义了模型-视图-控制...

Global site tag (gtag.js) - Google Analytics