java事务管理主要分成三个部分:JDBC,JTA,容器事务
他们之间的差异:
jdbc事务控制的局限性在一个数据库链接内,但是其使用简单
jta事务的功能强大,事务可以跨越多个数据库或者多个DAO,但是使用也比较复杂
容器事务,主要是指j2ee应用服务器提供的事务管理局限于EJB应用的使用(spring的事务管理)
JDBC:
在Java中使用事务处理,首先要求数据库支持事务。如使用MySQL的事务功能,就要求MySQL的表类型为Innodb才支持事务。否则,在Java程序中做了commit或rollback,但在数据库中根本不能生效。
在Connection类中提供了3个控制事务的方法:
(1) setAutoCommit(Boolean autoCommit):设置是否自动提交事务;
(2) commit();提交事务;
(3) rollback();回滚事务;
在jdbc api中,默认的情况为自动提交事务,也就是说,每一条对数据库的sql语句代表一项事务,操作成功后,系统自动调用commit()来提交,否则将调用rollback()来撤消事务。
在jdbc api中,可以通过调用setAutoCommit(false) 来禁止自动提交事务。然后就可以把多条更新数据库的sql语句做为一个事务,在所有操作完成之后,调用commit()来进行整体提交。倘若其中一项 sql操作失败,就不会执行commit()方法,而是产生相应的sqlexception,此时就可以捕获异常代码块中调用rollback()方法撤消事务。
事务处理为什么要在servie层呢,而不是在DAO层?
首先,在service层,基本上是每一个方法都对应着一个具体的业务,有些时候,一个业务可能需要操作到不同的表,也就是用到不同的DAO接口,所以事务处理最好是在service层。
由于jdbc事务管理的缺陷是只能针对同一个数据库链接中,所以如果需要从两个或以上的数据库里取得数据的话,会有很大的缺陷,针对需要查询两个或以上数据库的时候(也叫分布式事务),幸运的是通常情况下,JavaEE兼容的应用服务器,例如:Weblogic,Websphere,JBoss,Glassfish等都有这种分布式事务处理的组件。
JTA:
Java事务API(JTA;Java Transaction API)和它的同胞Java事务服务(JTS;Java Transaction Service),为J2EE平台提供了分布式事务服务。一个分布式事务(distributed transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。一个资源管理器(resource manager)是任意类型的持久化数据存储。事务管理器(transaction manager)承担着所有事务参与单元者的相互通讯的责任。JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。
在使用中,我们需要使用UserTransaction这个类,里边有这几个方法:
begin:开启一个事务
commit:提交当前事务
rollback:回滚当前事务
setRollbackOnly:把当前事务标记为回滚
setTransactionTimeout:设置事务的事件,超过这个事件,就抛出异常,回滚事务
使用了UserTransaction就能把普通的JDBC操作直接转成JTA操作,JTA对DataSource、Connection和Resource 都是有要求的,只有符合XA规范,并且实现了XA规范的相关接口的类才能参与到JTA事务中来,目前主流的数据库都支持XA规范。
下面是一个示例:
public void JtaTransfer() {
javax.transaction.UserTransaction tx = null;
java.sql.Connection conn = null;
try{
tx = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction"); //取得JTA事务,本例中是由Jboss容器管理
javax.sql.DataSource ds = (javax.sql.DataSource) context.lookup("java:/XAOracleDS"); //取得数据库连接池,必须有支持XA的数据库、驱动程序
tx.begin();
conn = ds.getConnection();
// 将自动提交设置为 false,
//若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交
conn.setAutoCommit(false);
stmt = conn.createStatement();
// 将 A 账户中的金额减少 500
stmt.execute("\
update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmt.execute("\
update t_account set amount = amount + 500 where account_id = 'B'");
// 提交事务
tx.commit();
// 事务提交:转账的两步操作同时成功
} catch(SQLException sqle){
try{
// 发生异常,回滚在本事务中的操做
tx.rollback();
// 事务回滚:转账的两步操作完全撤销
stmt.close();
conn.close();
}catch(Exception ignore){
}
sqle.printStackTrace();
}
}