问题描述
最近在项目里遇到了一个问题,新系统持久化使用的是hibernate3,但是为了实现一些功能必须调用一个另外的老系统(和新系统是同一个数据库,部署在同一个wls的domain下)的jar包内提供的方法,但是这个老的系统持久化使用的是jdbc的方式连接的数据库,但是数据源的获取方式和新系统一样,都是通过jndi从wls上查找。可是这样就产生了事务问题,hibernate3的事务提交都是用spring控制的,而老系统的jar方法必须要手动commit才能提交事务,可是这样,一旦hibernate的事务异常,产生了回滚,jar包提供的方法持久化的数据就无法回滚。各位持久化方面的大师,有没有什么好的建议,怎么解决这个问题,或者有其他的方法让hibernate和jdbc的方式和平共处。问题补充:感谢各位的关注,不过我找到了一个刚好的方法,Spring里有个DataSourceUtil的类,通过getConnection方法可以把当前连接和当前线程绑定,这样两种持久化的方式使用的是同一个connection,也就达到了事务一致。
解决方案
可以用JOTM或者类似的JTA来做这个事情。也就是说把JDBC和Hibernate当成跨数据库事务来做,就算是同一个数据库schema。下面一JOTM为例子。<?xml version="1.0" encoding="UTF-8"?><beans> <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/><!-- transactionManagerHibernate 这个作为Hibernate的transactionManager --> <bean id="transactionManagerHibernate" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm"/> </bean><!-- 内部数据源 1 --> <bean id="innerDataSourceJDBC" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm"/> <property name="driverName" value="..."/> <property name="url" value="..."/> <property name="user" value="..."/> <property name="password" value="..."/> </bean><!-- 用继承这个类改写,并实现InitializingBean,在afterProperty把这个数据绑定到JDBC要用到的JNDI名字上!!! --> <bean id="dataSourceJDBC" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource" ref="innerDataSource"/> <property name="user" value="..."/> <property name="password" value="..."/> <property name="maxSize" value="..."/> </bean> <!-- 内部数据源 2 --> <bean id="innerDataSourceHibernate" class="org.enhydra.jdbc.standard.StandardXADataSource" destroy-method="shutdown"> <property name="transactionManager" ref="jotm"/> <property name="driverName" value="..."/> <property name="url" value="..."/> <property name="user" value="..."/> <property name="password" value="..."/> </bean><!-- 把此数据源给spring内的Hibernate使用,替换原来从JNDI获得的数据源。 --> <bean id="dataSourceHibernate" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown"> <property name="dataSource" ref="innerDataSourceHibernate"/> <property name="user" value="..."/> <property name="password" value="..."/> <property name="maxSize" value="..."/> </bean> </beans>原理:从上面两个数据源获得的数据库连接(都是org.enhydra.jdbc.standard.StandardXAConnection)都在JTA控制之下,其中一个连接失败,那么另外一个会回滚。难点是将spring的数据源绑定到JNDI,因为我没做过。。。。
解决方案二:
让老系统的Service提供一个方法, 只是用于抛出一个异常.新系统的servcie发现这边抛了异常, 直接调用老系统的service 让它也抛一个异常.理论上最简单,最可行.等你真正要研究 Hibernate和JDBC整合的时候,再用楼上的代码即可.
解决方案三:
Hibernate回调JDBC模板