程序中使用JTA及其注意的地方

来源:互联网 发布:数据库应用账户管理 编辑:程序博客网 时间:2024/06/03 16:56
 
在我的以前的blog中曾多次谈到了跨数据库的事务(即分布式事务),的确这个方面可能在平时的应用中遇到的不多,但在一些比较大型的项目中或是多系统合作的条件下还是会碰到的。
J2EE下这个问题的解决有两种方案:一是采用EJB,利用容器去管理,我们把针对多个数据库的操作方法放到session bean的一个方法中,当和数据库交互产生问题时抛出EJBException,通知容器,则可以做到整个事务的回滚,在这里要注意一点的是我们的数据源配置要用XA的数据源配置(具体的可以看Jboss中的例子),不过你用普通的数据源也可以做到回滚,但容器在装载应用程序和EJB时会给出警告,说明在可能的情况下不能做到事务的整个回滚,所以我们还是用XA的数据源比较稳妥。
另一种方法是不用EJB容器的自动管理,自己在代码中手动调用JTAAPI来实现分布式事务的管理,要能这样做,首先你使用的J2EE服务器要提供JTA的实现,数据库和数据库驱动程序都要支持XA的事务。我在实践中测试用的是JBoss4.0.2SQL Server2000jtds 1.2的组合,没有问题。
首先我们要找到容器提供的事务管理器,
InitialContext jndiContext = new InitialContext();
UserTransaction  utx = (javax.transaction.UserTransaction) jndiContext.lookup(
                                          "java:comp/UserTransaction");
当程序找到UserTransaction后就可以开始分布式事务了。
try{
utx.begin()
……… //针对多个数据库的操作
utx.commit();
}
catch(Exception e){
utx.rollback();
}
以上就是通过程序来实现分布式的事务处理。
在这个有几个细节要注意:
一是我们在事务中要处理的数据库的连接的建立要放在utx.begin( )之后,不能建立在事务开始之前,否则事务是会失效的(这个也很好理解,在我上篇blog中讲的XA事务的实现逻辑中就能找到答案);但特别的是数据库的连接建立要在事务开始之后,但其关闭却不用在事务结束之前,也就是说我在事务中建立的conn,可以在事务完成后仍保持连接继续使用,而不是像有些资料所说事务的生命周期一定要长于conn的生命周期。
另外一点要注意的是在JTA的事务中不能再有JDBC的事务,比如在上面utx.begin( )之后,我对一个数据库的操作有多起,那这几起中我再使用JDBC的事务,如conn.commit( ),conn.rollback( )等,这是不行的,程序会报错。但当我的JTA的事务处理完后,也就是utx.commit( )后再对某个conn的操作,我仍可以使用JDBC的事务了。也就是说实际上一个XA的连接(XA数据源产出的连接)我完全能将其看作是一个非XA的连接(普通的数据源产生的连接),但是返过来却不能,非XA的连接不能参与JTA的事务(至少会给出警告)!