JTA和EJB的一些困惑,请高手解答!~

Class A(){
...
javax.transaction.UserTransaction tx = new InitialContext().lookup ("javax.transaction.UserTransaction");
tx.begin();
EJB1();
EJB2();
...
if(error){
tx.rollback();
}else{
tx.commit();
}

EJB1(){
...
Connection con = ds.getConnection();
//执行插入更新操作
con.close(); //?关闭后能提交吗
}
请教各位高手,我有一些疑问,当使用JTA来控制全局事务时,调用EJB1时,EJB1做执行更新插入操作,操作完数据库连接不是要释放掉吗?如果释放掉,全局事务提交还起作用吗?数据库连接是建基于XA的,如果处理关闭问题呢?在线等回答~!!
[该贴被admin于2009-04-17 20:17修改过]
[该贴被admin于2009-04-19 07:14修改过]

你需要了解一下EJB事务,看看精通EJB就可以
JTA一般是扁平事务,ejb1 ejb2的事务可配置为required.NEW等,可以加入当前JTA事务。

需要JTA事务起作用,数据库的DS获得必须使用容器的JNDI,这样JTA事务才会有效,那么数据库关闭对JTA事务不一定提交,只有commit之后才真正提交。具体自己可以测试一下。

不会提交的,只不过调用XRourse.end(Xid)方法而已,标记这个事务的一部分,然后EJB2方法调用开始的时候,事务管理器调用XAResource.start(Xid)方法,等EJB2调用结束后,XAResource.end(Xid),这样在你整整commit的时候,依次调用每个XAResource的prepare(Xid),如果返回OK,那么提交,否则只有有一个失败,都失败,这其实就是2PC,两阶段提交协议,JTA规范写的很清楚的。

谢谢banq和xmuzyu的解答!
可能我的问题没描述清楚。我这个应用是分布式跨多数据库的,需要一个中心端来做事务总控,所以采用JTA。EJB是调用远程的具体业务服务,EJB服务与后台数据库交互是采用jdbc,每次从jndi取连接,执行完不是要close。如果不close,就没法释放连接。如果close的话,全局事务是不是没法提交?疑问就是在这。

你的JNDI DS得到的connection是真正的connection的代理,你close仅仅只是释放了连接到DS,然后下个EJB方法调,JTA事务管理器会给你另外一个connection,并且需要注意的是JTA中,每个connecton(XAConnection)都会与一个XAResource(关联),这样每次方法调用开始时,JTA事务管理器调用XAResource.start(Xid)方法标记事务开始,方法调用结束后,调用XAReource.end(Xid)方法标记事务结束,等你最后用JNDI暴漏的UserTransaction.commit的时候,JTA事务分布式协调器会让与每个XAResource关联的事务管理调用相应的XAResource.prepare(Xid)方法,如果每个事务管理器都回答OK,那么就调用XAResource.commit方法来提交事务。所以JTA事务中,你获得东西都是已经被装饰了的,事务有JTA事务管理器管理,并且一般还有个JTA事务分布式协调器的概念(这个一般是APP SERVER).

再次谢谢xmuzyu的耐心解答!
JTA事务管理器会给你另外一个connection,对你这句话还是不解?ejb1的connection是取远程数据库的连接,这个是由JTA来管理的吗?

实现程序大致如下,这样对吗?


//中心端
...
javax.transaction.UserTransaction ut = new InitialContext().lookup (
"javax.transaction.UserTransaction");
ut.begin();
EJB1();
EJB2();
...
if(error){
tx.rollback();
}else{
tx.commit();
}
//远程服务1
EJB1(){
...
Connection con = ds.getXAConnection();
//执行插入更新操作
//关闭连接
con.close();
}




>>ejb1的connection是取远程数据库的连接,这个是由JTA来管理的吗?
是的,所有的连接其实都是有JTA事务管理器管理的,注意的是:一般连接的管理是由TransactionSynchronizationRegistry这个接口的实现来管理的,这个实现类,如果你采用APP SERVER(比如jboss),那么这个实现类就由jboss来实现了,如果你采用开源的JTA产品比如JTOM,那么这个类就由JTOM实现了。

前面那个帖子也说了,你没获取一个connection,那么事务管理器就需要相应的XAResource与之对应(而这些XAconnection以及XAResource等的都是你的JDBC驱动实现的)。所以如果你的EJB1方法和EJB2访问的是同一个数据库的话,那么连接应该是同一个,这些其实都不需要你管的,这些都是透明的,不同的app server采取不同的实现,但是如果你的ejb1,ejb2访问两个不同的数据库,那么获得的连接就是不同的,这些其实也是透明的。具体实现的时候,一般都是在你调用tx.begin()的时候,app server会开启一个事物,并分配一个Xid给当前事务,并且将事务绑定到当前的线程,当你最后commit的时候,在通知各个资源管理器来采用2PC协议提交。

不知道你清楚了没有,如果还不清楚,你可以看看JTA规范,里面写的很清楚。

还是不太清楚,过段时间得去看看JTA规范。最近由于急着完成工作,没啥时间去看资料,直接上来问了。
我ejb1和ejb2是远程服务对象,当中心端调用远程ejb时,运行的时候应该在远程服务器端上,取远程服务器上的连接进行数据库操作。我那两个程序片段是分布在两个应用不同的应用服务器,不知道是不是我的架构有问题,还是我一直没把问题说清楚,呵呵~现在在宿舍没法测试代码,只能等下周一了。