JDBCTemplate和HibernateTemplate事物原始碼解析
由於專案中對批量的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
publicabstract
/**/ {
/*77 */privatestaticfinal Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
/**/
/*80 */privatestaticfinal ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
/**/
/* 83 */privatestatic
/**/
/*86 */privatestaticfinal ThreadLocal<String> currentTransactionName = new NamedThreadLocal("Current transaction name");
/**/
/*89 */privatestaticfinal ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal("Current transaction read-only status");
/**/
/*92 */privatestaticfinal ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level");
/**/
/*95 */privatestaticfinal 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的時候。
在事物的完整性方面來說是沒有問題的。下面我們在看看org.springframework.orm.hibernate3.HibernateTransactionManager。
.HibernateTransactionManager的父類是PlatformTransactionManager。
.HibernateTransactionManager有很多子類,實現了事物的管理:
CciLocalTransactionManage.
DataSourceTransactionManage.
HibernateTransactionManage.
JdoTransactionManage.
JpaTransactionManage.
publicabstractinterface PlatformTransactionManager
{
//事物狀態
publicabstract TransactionStatus getTransaction(TransactionDefinition paramTransactionDefinition)
throws TransactionException;
//提交
publicabstractvoid commit(TransactionStatus paramTransactionStatus)
throws TransactionException;
//回滾
publicabstractvoid rollback(TransactionStatus paramTransactionStatus)
throws TransactionException;
}
/**/publicclass HibernateTransactionManager extends AbstractPlatformTransactionManager
/**/implements ResourceTransactionManager, BeanFactoryAware, InitializingBean
/**/ {
在這些事物管理實現類中都使用了 TransactionSynchronizationManager.bindResource(key);來獲取當前繫結的物件;如SessionHolder
/**/protected Object doGetTransaction()
/**/{
/* 430 */HibernateTransactionObject txObject = new HibernateTransactionObject(null);
/* 431 */ txObject.setSavepointAllowed(isNestedTransactionAllowed());
/**/
/* 433 */SessionHolder sessionHolder =
/* 434 */(SessionHolder)TransactionSynchronizationManager.getResource(getSessionFactory());
/* 435 */if (sessionHolder != null) {
/* 436 */if (this.logger.isDebugEnabled()) {
/* 437 */this.logger.debug("Found thread-bound Session [" +
/* 438 */SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
/**/}
/* 440 */txObject.setSessionHolder(sessionHolder);
/**/}
/* 442 */elseif (this.hibernateManagedSession) {
/**/try {
/* 444 */Session session = getSessionFactory().getCurrentSession();
/* 445 */if (this.logger.isDebugEnabled()) {
/* 446 */this.logger.debug("Found Hibernate-managed Session [" +
/* 447 */SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
/**/}
/* 449 */txObject.setExistingSession(session);
/**/}
/**/catch (HibernateException ex) {
/* 452 */thrownew DataAccessResourceFailureException(
/* 453 */"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
/**/}
/**/}
/**/
/* 457 */if (getDataSource() != null) {
/* 458 */ConnectionHolder conHolder = (ConnectionHolder)
/* 459 */TransactionSynchronizationManager.getResource(getDataSource());
/* 460 */txObject.setConnectionHolder(conHolder);
/**/}
/**/
/* 463 */return txObject;
/**/}
在Aop的事物管理中:通過攔截器來對相應的事物進行處理。
在對Spring AOP原始碼分析中關於AOP代理如何起作用時,我們知道Spring的AOP代理通過invoke回撥方法對切入點方法進行攔截處理,這個invoke方法是AOP聯盟的方法攔截器MethodInterceptor介面中定義的方法,用於對AOP代理物件的方法進行包裝處理。事務攔截器TransactionInterceptor正是通過這個invoke攔截方法實現事務的攔截處理,原始碼如下:
/**/publicclass TransactionInterceptor extends TransactionAspectSupport
/**/implements MethodInterceptor, Serializable{
1.//事務攔截器的攔截方法
2.public Object invoke(final MethodInvocation invocation) throws Throwable {
3.//通過AOP獲取事務的目標類
4.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
5.//通過事務屬性源TransactionAttributeSource讀取事務的屬性配置,即呼叫上面名稱匹配
6.//事務屬性源NameMatchTransactionAttributeSource的方法
7.final TransactionAttribute txAttr =
8.getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
9.//獲取Spring事務管理IoC容器配置的事務處理器
10.final PlatformTransactionManager tm = determineTransactionManager(txAttr);
11.//獲取目標類指定方法的事務連線點
12.final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass);
13.//區分不同型別的PlatformTransactionManager事務處理器,不同型別的事務處理器呼叫//方式不同。對CallbackPreferringPlatformTransactionManager,需要回調函式來//實現事務的建立和提交,對非CallbackPreferringPlatformTransactionManager來//說,則不需要使用回撥函式來實現事務處理。
14.//非CallbackPreferringPlatformTransactionManager型別的事務處理器
15.if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
16.//建立事務,將當前事務狀態和資訊儲存到TransactionInfo物件中
17.TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
18.Object retVal = null;
19.try {
20.//沿著攔截器鏈呼叫處理,使得最後目標物件的方法得到呼叫
21.retVal = invocation.proceed();
22.}
23.catch (Throwable ex) {
24.//在呼叫攔截器攔過程中出現異常,則根據事務配置進行提交或回滾處理
25.completeTransactionAfterThrowing(txInfo, ex);
26.throw ex;
27.}
28.//清除與當前執行緒繫結的事務資訊
29.finally {
30.cleanupTransactionInfo(txInfo);
31.}
32.//通過事務處理器來對事務進行提交
33.commitTransactionAfterReturning(txInfo);
34.return retVal;
35.}
36.//CallbackPreferringPlatformTransactionManager型別的事務處理器
37.else {
38.//通過回撥函式對事務進行處理
39.try {
40.//執行實現TransactionCallback介面的doInTransaction回撥方法
41.Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
42.new TransactionCallback<Object>() {
43.//實現TransactionCallback介面匿名內部類的回撥方法
44.public Object doInTransaction(TransactionStatus status) {
45.//建立和準備事務
46.TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
47.try {
48.//沿著攔截器攔呼叫
49.return invocation.proceed();
50.}
51.//攔截器鏈處理過程中產生異常
52.catch (Throwable ex) {
53.//如果事務對異常進行回滾處理
54.if (txAttr.rollbackOn(ex)) {
55.//如果異常時執行時異常,則事務回滾處理
56.if (ex instanceof RuntimeException) {
57.throw (RuntimeException) ex;
58.}
59.//如果不是執行時異常,則提交處理
60.else {
61.thrownew ThrowableHolderException(ex);
62.}
63.}
64.//如果事務對異常不進行回滾處理
65.else {
66.//提交處理
67.returnnew ThrowableHolder(ex);
68.}
69.}
70.//清除當前執行緒繫結的事務資訊
71.finally {
72.cleanupTransactionInfo(txInfo);
73.}
74.}
75.});
76.//對呼叫結果異常進行處理。
77.//如果是ThrowableHolder型別的異常,則轉換為Throwable丟擲
78.if (result instanceof ThrowableHolder) {
79.throw ((ThrowableHolder) result).getThrowable();
80.}
81.//如果不是ThrowableHolder型別的異常,則異常不做處理直接丟擲
82.else {
83.return result;
84.}
85.}
86.catch (ThrowableHolderException ex) {
87.throw ex.getCause();
88.}
89.}
90.}
completeTransactionAfterThrowing()是事物回滾方法。呼叫的是父類的方法。
/**/publicabstractclass TransactionAspectSupport
/**/implements BeanFactoryAware, InitializingBean
/**/ {
protectedvoid completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex)
/**/{
/* 404 */if ((txInfo != null) && (txInfo.hasTransaction())) {
/* 405 */if (this.logger.isTraceEnabled()) {
/* 406 */this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
/* 407 */"] after exception: " + ex);
/**/}
/* 409 */if (txInfo.transactionAttribute.rollbackOn(ex)) {
/**/try {
//這裡呼叫的是: AbstractPlatformTransactionManager的rollback方法。最終呼叫的相應的子類的doRollback方法。
//比如用的是hibernateTranactionManager就是呼叫其中的doRollback方法。
// txObject.getSessionHolder().getTransaction().rollback();這裡最終呼叫的還是Hibernate中Transaction的Rollback方法
//歸根揭底,都是呼叫了connection.rollback().DataSoucreTransactionManager也類似。
/* 411 */txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
/**/}
/**/catch (TransactionSystemException ex2) {
/* 414 */this.logger.error("Application exception overridden by rollback exception", ex);
/* 415 */ex2.initApplicationException(ex);
/* 416 */throw ex2;
/**/}
/**/catch (RuntimeException ex2) {
/* 419 */this.logger.error("Application exception overridden by rollback exception", ex);
/* 420 */throw ex2;
/**/}
/**/catch (Error err) {
/* 423 */this.logger.error("Application exception overridden by rollback error", ex);
/* 424 */throw err;
/**/}
/**/}