JDBCTemplate和HibernateTemplate事物源码解析 - - ITeye技术网站
由于项目中对批量的sql进行入库处理。所以打算用jdbcTemplate。在其他的增删改查中都是用hibernateTemplate。
在这里考虑到一个问题,就是当jdbcTemplate和hibernateTemplate结合用的时候,事务是怎么样的了?
经过测试:在一个方法中同时使用jdbcTemplate,和hibernateTemplate对数据进行增加操作。然后抛出异常。
发现事务是可以正常回滚的。但为什么可以这样了?看了下源码终于了解了一些。
<bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
</bean>
总而言之。不管是使用jdbcTemplate或者是hibernateTemplate都是对jdbc的封装,说白了,对数据库的操作还是
使用connection,在回滚事务的时候还是调用了connection. Rollback方法来进行回滚的。
这一回想,在hibernate中有个sessionFactory. getCurrentSession()方法。调用的当前的线程session。
意思就是用当前的connection来操作数据。
在spring管理中有这么一个类来进行当前线程的数据绑定:TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager
/* */ {
/* 77 */ private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
/* */
/* 80 */ private static final ThreadLocal<Map<Object, Object>> resources = newNamedThreadLocal("Transactional resources");
/* */
/* 83 */ private static final ThreadLocal<List<TransactionSynchronization>> synchronizations = newNamedThreadLocal("Transaction synchronizations");
/* */
/* 86 */ private static final ThreadLocal<String> currentTransactionName = newNamedThreadLocal("Current transaction name");
/* */
/* 89 */ private static final ThreadLocal<Boolean> currentTransactionReadOnly = newNamedThreadLocal("Current transaction read-only status");
/* */
/* 92 */ private static final ThreadLocal<Integer> currentTransactionIsolationLevel = newNamedThreadLocal("Current transaction isolation level");
/* */
/* 95 */ private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal("Actual transaction active");
在OpenEntityManagerInViewFilter,OpenSessionInViewInterceptor等需要获取当前线程对象的类中都用到了此类。
在使用hibernateTemplate可以使用hibernateTemplate.sessionFactory.getCurrentSession().connection获取当前的connection对象
在使用jdbcTemplate获取当前的connection对象的方法是:
public abstract class DataSourceUtils {
…
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//①首先尝试从事务同步管理器中获取数据连接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() ||
conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
//②如果获取不到连接,则直接从数据源中获取连接
Connection con = dataSource.getConnection();
//③如果拥有事务上下文,则将连接绑定到事务上下文中
if (TransactionSynchronizationManager.isSynchronizationActive()) {
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {holderToUse.setConnection(con);}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(
dataSource, holderToUse);
}
}
return con;
}
…
}
当在同在方法中打印出这两个种方法获取的connection对象是同一对象时,基本上证明了在使用jdbcTemplate和hibernateTemplate的时候。