这种场景下的事务如何控制?

10-03-19 javaRwx

下图是我目前一个项目中的应用场景和问题描述,请各位大侠指点!!

应用场景说明

1
javaRwx
2010-03-19 09:56
图片中红色字体部分正是我所遇见的问题

说明:如果大家看到的图片是个红叉,请右键点击显示图片即可(不知道是论坛的问题还是图片太大)。

[该贴被javaRwx于2010-03-19 10:03修改过]

banq
2010-03-19 10:26
架构搞得复杂,Spring + EJB是够复杂的。

无论你在Spring中还是在EJB的无态bean中使用事务,都属于JTA事务。statless session bean缺省是激活JTA事务的。

关键问题是:你的Spring使用的JTA事务场景要和EJB容器中事务场景一致,比如使用同一个JNDI源也许可以 。

如果不能合并JTA事务场景,也可以从设计上考虑合并一下,比如要么要EJB的无态Bean中的事务,要么完全使用Spring的事务,不过从你这个案例情况看,单单依靠Spring事务已经控制不住了,所以,就放弃这个业务的Spring事务,走向完全用EJB的无态Bean事务吧,效果都是一样。

另外,事务控制很好,会带来性能上的缺陷,看看"CAP定理",JTA事务和数据库事务是保证严格一致性,但是丧失可用性。

[该贴被banq于2010-03-19 10:37修改过]

javaRwx
2010-03-19 10:39
板桥大侠高见,有两点我不明白

1、为什么单单依靠Spring控制不住这种场景下的事务(我也测试过,发现的确不行),没有研究过用Spring代替EJB

2、你说的使用同一个JNDI源是指三个EJB服务使用同一个JNDI数据源吗?但是目前的情况是每个EJB都对应着自己的数据库啊

还请多指点!

congdepeng
2010-03-19 10:46
我不说话,我关注你们讨论

banq
2010-03-19 10:50
2010年03月19日 10:39 "javaRwx"的内容
你说的使用同一个JNDI源是指三个EJB服务使用同一个JNDI数据源吗?但是目前的情况是每个EJB都对应着自己的数据库啊 ...

是啊,JTA事务是跨数据库的,JTA事务是比基于数据库连接的JDBC事务更长的一种事务,可以跨多个数据库JDBC事务,每个JDBC事务的有效范围只能在JDBC连接开始和结束之间,如果需要保证两个JDBC事务的一致性原子性,那么就要使用JTA事务。

JTA事务是通过2PC两段事务来保证跨不同种类数据库操作的ACID的,但是性能很不好,具体使用比较方便,直接从context.lookup所用服务器的JTA的JNDI名称即可,当然,需要首先配置服务器的JTA的JNDI,你可以参考服务器文档。

现在关键是:EJB无态Bean服务调用JDBC时需要一个DataSource,这个JDBC的DATASoource你是从JNDI获得,还是自己定义的数据库连接,如果是从服务器的JNDI获得的,那么就是使用同一个JTA场景了,无论你使用多少EJB,缺省已经激活JTA事务了。

javaRwx
2010-03-19 11:09
2010年03月19日 10:50 "banq"的内容
EJB无态Bean服务调用JDBC时需要一个DataSource,这个JDBC的DATASoource你是从JNDI获得,还是自己定义的数据库连接,如果是从服务器的JNDI获得的,那么就是使用同一个JTA场景了,无论你使用多少EJB,缺省已 ...

这个DataSource我是通过在Spring中配置数据源的JNDI名字获得,配置如下:

// 在此输入java代码
<bean id="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
		<property name="jndiName" value="bagsglDS" />
		<property name="jndiEnvironment">
			<props>
				<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
				<prop key="java.naming.provider.url">t3://127.0.0.1:8001</prop>
				<prop key="java.naming.security.principal">weblogic</prop>
				<prop key="java.naming.security.credentials">weblogic</prop>
			</props>
		</property>
	</bean>
<p>

我在所有EJB服务中的无状态bean都是通过这种方式获取数据源的,但在EJB的部署描述文件中,并没有对EJB的事务进行配置

[该贴被javaRwx于2010-03-19 11:13修改过]

banq
2010-03-19 11:53
2010年03月19日 11:09 "javaRwx"的内容
有EJB服务中的无状态bean都是通过这种方式获取数据源的 ...

如果是这样OK,那就直接在EJB里调用其他EJB,应该都处于同一个事务边界内,你断点跟踪一下把,看看启动的是否同一个JTA监控线程。

javaRwx
2010-03-19 12:11
测试了一下,还是不行,我的EJB调用其他EJB是通过Spring进行调用的

说一下我的测试步骤:

1、我将EJB服务1、EJB服务2及EJB服务3均部署在不同的weblogic上,分别访问各自的数据库,访问数据库的方式统一使用Spring配置JNDI数据源的方式(在weblogic中配置数据源时,专门选择的oracle.jdbc.xa.client.OracleXADataSource驱动)

2、在EJB服务1中的doRegister方法中分别调用EJB服务2和EJB服务3中的方法实现注册业务,在提交时发现事务仍然没有被控制住

banq
2010-03-19 13:45
2010年03月19日 12:11 "javaRwx"的内容
我的EJB调用其他EJB是通过Spring进行调用的 ...

不要通过Spring调。

Spring ----> EJB
        |--> EJB
<p>

改为统一通过EJB调用,在EJB中获得JNDI datasource:

Spring ---> EJB ---->EJB
                  |->EJB
<p>

[该贴被banq于2010-03-19 13:45修改过]

javaRwx
2010-03-19 19:22
经过不断测试发现配置成org.springframework.transaction.jta.WebLogicJtaTransactionManager时,可以控制,但是在模拟ejb2插入数据失败时,WebLogic后台会报javax.transaction.TransactionRolledbackException异常,但从两个数据库中看事务却成功回滚了,异常信息如下:

<2010-3-19 下午06时59分47秒 CST> <Error> <HTTP> <BEA-101017> <[weblogic.servlet.
internal.WebAppServletContext@1b4268b - appName: 'WebContent', name: 'WebContent
', context-path: '/web1'] Root cause of ServletException.
javax.transaction.TransactionRolledbackException: EJB Exception: : org.springfra
mework.dao.DataIntegrityViolationException: SqlMapClient operation; SQL [];

现将两个EJB做为附件上传,麻烦板桥大哥给看看,提提意见

两个EJB调用关系说明:

ejb1.jar为主EJB,在ejb1.jar包中的IBoDM_DWLXImpl类中的insertDM_DWLX方法中除了调用本地Dao中的方法向本地数据库插入数据外,同时还调用了ejb2中的方法,向ejb2对应的数据库中插入数据


attachment:


ejb.rar

xmuzyu
2010-03-19 22:58
2010年03月19日 19:22 "javaRwx"的内容
在模拟EJB2插入数据失败时,WebLogic后台会报javax.transaction.TransactionRolledbackException异常,但从两个数据库中看事务却成功回滚了 ...

本来应该就是这样吧,数据库插入失败,事务当然回滚啊,还有JTA的时候,事务管理器肯定要根据appserver来配置的。

猜你喜欢