事务是不能嵌套的.只能将操作写到一个方法里.以下是单库.
手工实现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了。
分享到:
相关推荐
一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...
一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...
一个能够使其实现管理系统化、规范化、自动化的计算机系统就显得很有必要。利用计算机技术,实现管理系的自动化,规范化就是这个问题最好的解决方法. 论文主要探讨“房屋租赁管理系统”的理论基础和设计思想,根据系统...
本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。 本系统使有jsp进行网页界面的设计,使用MVC设计模式,...
本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。 本系统使有jsp进行网页界面的设计,使用MVC设计模式,...
近年来我国信息事业发展迅速,手工管理方式在绩效考核信息管理等需要大量事务处理的应用中已显得不相适应,采用IT技术提高服务质量和管理水平势在必行。目前,对外开放必然趋势使信息行业直面外国同行单位的直接挑战...
本系统中解决了学校图书管理事务中的常用基本问题以及相关统计工作。本系统中包含6个功能模块:系统设置,读者管理,图书管理,图书借还,系统查询和更改口令。 本系统使有jsp进行网页界面的设计,使用MVC设计模式,...
大家常规的做法是采用springjdbc来实现原生SQL编写,但是也同样存在问题,SQL无法分离也没有逻辑标签能力。所以为了解决这个痛病,Jeecg针对springjdbc + freemarker做封装,出了这么一个轻量级永久层,可以让...
35 基于JDBC 的事务管理机制................................................................ 35 基于JTA 的事务管理机制................................................................... 36 ...
MyBatis消除了几乎所有的JDBC代码和参数手工设置以及结果集检索。 数据库:通常使用MySQL或其他关系数据库来存储用户数据、预约信息、服务记录等。 前端技术:可能包括HTML, CSS, JavaScript及前端框架如Bootstrap或...
第一章 安装配置开发环境 18 1.1系统需求 18 1.2 JDK 的下载,安装和配置(可...10.7.2 MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 - 用 CGLIB 来实现事务管理 258 10.7.3 Spring相关的参考资料 261
20.5 Java应用通过Hibernate API声明JDBC事务 20.5.1 处理异常 20.5.2 Session与事务的关系 20.5.3 设定事务超时 20.6 Java应用通过Hibernate API声明JTA事务 20.7 Java应用通过JTA API声明JTA事务 ...
20.5 Java应用通过Hibernate API声明JDBC事务 20.5.1 处理异常 20.5.2 Session与事务的关系 20.5.3 设定事务超时 20.6 Java应用通过Hibernate API声明JTA事务 20.7 Java应用通过JTA API声明JTA事务 ...
20.5 Java应用通过Hibernate API声明JDBC事务 20.5.1 处理异常 20.5.2 Session与事务的关系 20.5.3 设定事务超时 20.6 Java应用通过Hibernate API声明JTA事务 20.7 Java应用通过JTA API声明JTA事务 ...
20.5 Java应用通过Hibernate API声明JDBC事务 20.5.1 处理异常 20.5.2 Session与事务的关系 20.5.3 设定事务超时 20.6 Java应用通过Hibernate API声明JTA事务 20.7 Java应用通过JTA API声明JTA事务 ...
1.3.2 用SQL/JDBC手工编写持久层 1.3.3 使用序列化 1.3.4 面向对象的数据库系统 1.3.5 其他选项 1.4 ORM 1.4.1 什么是ORM 1.4.2 一般的ORM问题 1.4.3 为什么选择ORM 1.4.4 ...
31、EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的? SessionBean: Stateless Session Bean 的生命周期是由容器决定的,当客户机发出请求要建立一个Bean的实例时,EJB容器不一定要创建...