1. 程式人生 > >JDBCTemplate和HibernateTemplate事物原始碼解析

JDBCTemplate和HibernateTemplate事物原始碼解析

由於專案中對批量的sql進行入庫處理。所以打算用jdbcTemplate。在其他的增刪改查中都是用hibernateTemplate

在這裡考慮到一個問題,就是當jdbcTemplatehibernateTemplate結合用的時候,事物是怎麼樣的了?

經過測試:在一個方法中同時使用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

class TransactionSynchronizationManager

/**/ {

/*77 */privatestaticfinal Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

/**/

/*80 */privatestaticfinal ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");

/**/

/* 83 */privatestatic

final ThreadLocal<List<TransactionSynchronization>> synchronizations = new NamedThreadLocal("Transaction synchronizations");

/**/

/*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");

OpenEntityManagerInViewFilterOpenSessionInViewInterceptor等需要獲取當前執行緒物件的類中都用到了此類。

在使用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物件是同一物件時,基本上證明了在使用jdbcTemplatehibernateTemplate的時候。

在事物的完整性方面來說是沒有問題的。下面我們在看看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代理如何起作用時,我們知道SpringAOP代理通過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 {

//這裡呼叫的是: AbstractPlatformTransactionManagerrollback方法。最終呼叫的相應的子類的doRollback方法。

//比如用的是hibernateTranactionManager就是呼叫其中的doRollback方法。

// txObject.getSessionHolder().getTransaction().rollback();這裡最終呼叫的還是HibernateTransactionRollback方法

//歸根揭底,都是呼叫了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;

/**/}

/**/}