论坛首页 Java企业应用论坛

Spring真的能mixed JDBC和ORM?

浏览 25402 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2005-03-02  
干嘛要用JdbcTemplate呀,session.connection()呀
0 请登录后投票
   发表时间:2005-03-03  
楼主以及二楼的朋友的论断错误倒也罢了,那种肯定的,结论性总结的态度很容易误导初学者的学习和理解。

提个小小的建议:下结论前要进行充分的考证,我们技术工作者尤其需要严谨的态度。需要用证据来说话。

jdo dao和jdbc dao能否在同一个事务里这我不太清楚。因为我没用过jdo daosupport。
但是jdbc daosupport和hibernate daosupport却能被wrap到同一个事务里。成立需要几点条件:
1、使用同一个datasource
2、事务交由hibernateTransactionManager管理
3、相关dao以及service需要使用runtime exception体系,使用spring提供的exception可以,自己封装设计的runtime exception体系也行。

与此相关的事务代码片断在HibernateTransactionManager类中。最好可以把DatasourceTransactionManager和HibernateTransactionManager对比来看。
在此贴上几个源码片断,多余的我就不解释了。相信大家一看自明。
HibernateTransactionManager#doGetTransaction
		HibernateTransactionObject txObject = new HibernateTransactionObject();;
		txObject.setSavepointAllowed(isNestedTransactionAllowed(););;

		if (TransactionSynchronizationManager.hasResource(getSessionFactory(););); {
			SessionHolder sessionHolder =
					(SessionHolder); TransactionSynchronizationManager.getResource(getSessionFactory(););;
			if (logger.isDebugEnabled();); {
				logger.debug("Found thread-bound session [" + sessionHolder.getSession(); +
						"] for Hibernate transaction");;
			}
			txObject.setSessionHolder(sessionHolder, false);;
			if (getDataSource(); != null); {
				ConnectionHolder conHolder = (ConnectionHolder);
						TransactionSynchronizationManager.getResource(getDataSource(););;
				txObject.setConnectionHolder(conHolder);;
			}
		}

		return txObject;

由此可以看出hibernateTransactionManager可以检测到绑定在当前线程上的connection

HibernateTransactionManager#doBegin
			Connection con = session.connection();;
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);;
			txObject.setPreviousIsolationLevel(previousIsolationLevel);;

..............

			if (getDataSource(); != null); {
				ConnectionHolder conHolder = new ConnectionHolder(con);;
				if (definition.getTimeout(); != TransactionDefinition.TIMEOUT_DEFAULT); {
					conHolder.setTimeoutInSeconds(definition.getTimeout(););;
				}
				if (logger.isDebugEnabled();); {
					logger.debug("Exposing Hibernate transaction as JDBC transaction [" +
							conHolder.getConnection(); + "]");;
				}
				TransactionSynchronizationManager.bindResource(getDataSource();, conHolder);;
				txObject.setConnectionHolder(conHolder);;
			}
			// bind the session holder to the thread
			if (txObject.isNewSessionHolder();); {
				TransactionSynchronizationManager.bindResource(getSessionFactory();, txObject.getSessionHolder(););;
			}

由此可以看出,在真正启动一个事务时,hbTxnManager会先把connection绑定到当前线程,再绑定session到当前线程,由TransactionSynchronizationManager统一管理。并且上面提到的connection是从session中取得的,也就是说,无论是jdbc dao还是hibernate dao本质上使用的是同一个database connection

因此得出结论:HibernateTransactionManager实际上是可以同时管理由JdbcTemplate或JdbcDaoSupport实现的dao以及HibernateTemplate或HibernateDaoSupport实现的事务的。


Rod Johnson的话:
引用
It is possible--and sometimes useful--to have coordinated transactions for both. Your JDBC transactions will be managed by the HibernateTransactionManager if you work with the same JDBC DataSource in the same transaction. That is, create the SessionFactory using Spring's SessionFactoryBean using the same DataSource that your JdbcTemplates use.

The only issue to watch, of course, is that you may be invalidating your Hibernate cache by JDBC changes. Generally I find it best to use JDBC to update only tables that don't have Hibernate mappings.


Juergen Hoeller的话:
引用
As Rod said, simply keep using HibernateTransactionManager, which auto-detects the DataSource used by Hibernate and seamlessly exposes Hibernate transactions as JDBC transactions for that DataSource. JDBC code that accesses the same DataSource via Spring will automatically participate in such transactions.

Note that you must specify the DataSource for Hibernate via LocalSessionFactoryBean's "dataSource" property to allow HibernateTransactionManager to auto-detect it. Alternatively, you can explicitly pass the DataSource to HibernateTransactionManager's "dataSource" property.
0 请登录后投票
   发表时间:2005-03-03  
谢谢楼上的严谨的作风

但是
void doBusiness(){
doAction1(); 使用JdbcTemplete
doAction2(); 使用JdoDaoSupport或HBDaoSupport
}

请注意执行的顺序,是先执行jdbcTemplate,再执行O/R
Dao support

而且你单单看hibernateTransactionManager是不够的
你看看JDBC的TransactionManager...
0 请登录后投票
   发表时间:2005-03-03  
和执行顺序有什么关系?至于和DatasourceTranactionManager就更没有关系了。事实上,当你把jdbcTemplate dao和hibernate dao放置在同一个service的方法里时,你是不需要在spring的配置文件里声明DatasourceTransactionManager bean的。
实在很难理解你的真正含义。

你应该只是停留在思考的程度吧?建议你具体实践一下。实践以后如果还有此类问题也请拿出具体代码来说明。流于口头上的争论实在是没有意义,请就此打住。呵呵~~

good luck
0 请登录后投票
   发表时间:2005-03-03  
谢谢,我又仔细浏览了JdoDaoSupport和HbDaoSupport的TransactionManager,呵呵,

关于,---mixed ORM and JDBC usage is a feature of Spring DAO 这句话,还是要打半个问号,
jdbc+Jdo默认是无法混合的,

JDOTransactionManager.java

/ Register the JDO PersistenceManager's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
ConnectionHandle conHandle = getJdoDialect().getJdbcConnection(pm, definition.isReadOnly());
if (conHandle != null) {
ConnectionHolder conHolder = new ConnectionHolder(conHandle);


DefaultJdoDialect.java
/**
* This implementation returns null, to indicate that JDBC Connection
* retrieval is not supported.
*/
public ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly)
throws JDOException, SQLException {
return null; //直接返回一个null,
}

由于jdo获得PM相关的conn是由不同厂商实现的,所以spring无法支持..(我上面也说了)...


没错,Hibernate mixed jdbc的确是可以的,是我看的不仔细,因为我项目里用的是Spring + kodo jdo..

:)当然,我们可以复写这个方法,把PM cast成kodoPM
然后把connection取出来. Spring还是给我们提供了扩展的方法.
0 请登录后投票
   发表时间:2005-03-03  
还有个问题呀,如果你用了hibernate second level,这时JdbcTemplate去更新了数据,那你怎么样同步呢?
除非像Rod Johnson说的:
引用

Generally I find it best to use JDBC to update only tables that don't have Hibernate mappings.

要不就还是session.connection()吧
0 请登录后投票
   发表时间:2005-03-04  
denis教育的对,源代码我也看过,不过看得不仔细,所以得出了错误的结论。
偶认错。。
0 请登录后投票
   发表时间:2007-07-10  
denis 写道


Rod Johnson的话:
引用
It is possible--and sometimes useful--to have coordinated transactions for both. Your JDBC transactions will be managed by the HibernateTransactionManager if you work with the same JDBC DataSource in the same transaction. That is, create the SessionFactory using Spring's SessionFactoryBean using the same DataSource that your JdbcTemplates use.

The only issue to watch, of course, is that you may be invalidating your Hibernate cache by JDBC changes. Generally I find it best to use JDBC to update only tables that don't have Hibernate mappings.


Juergen Hoeller的话:
引用
As Rod said, simply keep using HibernateTransactionManager, which auto-detects the DataSource used by Hibernate and seamlessly exposes Hibernate transactions as JDBC transactions for that DataSource. JDBC code that accesses the same DataSource via Spring will automatically participate in such transactions.

Note that you must specify the DataSource for Hibernate via LocalSessionFactoryBean's "dataSource" property to allow HibernateTransactionManager to auto-detect it. Alternatively, you can explicitly pass the DataSource to HibernateTransactionManager's "dataSource" property.



按照spring文档建议的方式,jdbc,hibernate session拿的是同一个connection,这样事务控制有一定保证。
jdbc,hibernate session mixed有什么样的问题呢?我分析大体有一下几点:
1. session缓存和二级缓存与jdbc数据不一致;session中拿到数据后mapping的对象可能会被jdbc修改,而session不知道;反之同理。
2. 更新执行冲突;hibernate session与数据库同步有对数据库更新操作的 执行策略,jdbc是立刻执行的,两者可能冲突。
0 请登录后投票
   发表时间:2007-07-10  
这里边确实是有一些问题的,hibernate的更新数据可以通过显式的flush来刷出到数据库,但是jdbc的修改hibernate的缓存是不知道的。除非有一个全局的考虑,考虑到什么时候hibernate的缓存可能是不对的,需要清除,安排好具体执行步骤,这样才能用好。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics