spring 註解 事務和宣告式事務共存的情況下如何決定先後順序
首先先看配置檔案:
[html] view plain copy print?- <!– hibernate –>
- <beanid=“sessionFactory”
- class=“org.springframework.orm.hibernate3.LocalSessionFactoryBean”>
- <propertyname=“dataSource”ref=“dataSource”/>
- <propertyname=“hibernateProperties”>
- <props>
- <propkey=“hibernate.hbm2ddl.auto”>update</prop>
- <propkey=“hibernate.show_sql”>true</prop>
- <propkey=“hibernate.format_sql”>true</prop>
- <propkey=“connection.autoReconnect”>true</prop>
- <
- <propkey=“connection.is-connection-validation-required”>true</prop>
- <propkey=“hibernate.dialect”>org.hibernate.dialect.MySQLDialect</prop>
- </props>
- </property>
- <propertyname=“mappingDirectoryLocations”>
- <list>
- <value>classpath*:*oddtech/bean</value>
- </list>
- </property>
- </bean>
- <!– 事務管理 –>
- <beanid=“txManager”
- class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>
- <propertyname=“sessionFactory”ref=“sessionFactory”/>
- </bean>
- <!– 註解式事務的支援 –>
- <tx:annotation-driventransaction-manager=“txManager”order=“0”/>
- <!– 服務事務註冊切面 –>
- <aop:config>
- <aop:pointcutexpression=“execution(* oddtech.service.impl.*.*(..))”
- id=“txPoint”/>
- <aop:advisoradvice-ref=“txAdvice”pointcut-ref=“txPoint”order=“1”/>
- </aop:config>
- <tx:advicetransaction-manager=“txManager”id=“txAdvice”>
- <tx:attributes>
- <tx:methodname=“find*”propagation=“REQUIRED”read-only=“true”
- rollback-for=“Exception”/>
- <tx:methodname=“select*”propagation=“REQUIRED”read-only=“true”
- rollback-for=“Exception”/>
- <tx:methodname=“insert*”propagation=“REQUIRED”
- rollback-for=“Exception”/>
- <tx:methodname=“delete*”propagation=“REQUIRED”
- rollback-for=“Exception”/>
- <tx:methodname=“update*”propagation=“REQUIRED”
- rollback-for=“Exception”/>
- <tx:methodname=“modify*”propagation=“REQUIRED”
- rollback-for=“Exception”/>
- <tx:methodname=“*”read-only=“true”
- rollback-for=“Exception”/>
- </tx:attributes>
- </tx:advice>
<!-- hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="connection.autoReconnect">true</prop>
<prop key="connection.autoReconnectForPools">true</prop>
<prop key="connection.is-connection-validation-required">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="mappingDirectoryLocations">
<list>
<value>classpath*:*oddtech/bean</value>
</list>
</property>
</bean>
<!-- 事務管理 -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 註解式事務的支援 -->
<tx:annotation-driven transaction-manager="txManager" order="0"/>
<!-- 服務事務註冊切面 -->
<aop:config >
<aop:pointcut expression="execution(* oddtech.service.impl.*.*(..))"
id="txPoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint" order="1"/>
</aop:config>
<tx:advice transaction-manager="txManager" id="txAdvice">
<tx:attributes >
<tx:method name="find*" propagation="REQUIRED" read-only="true"
rollback-for="Exception" />
<tx:method name="select*" propagation="REQUIRED" read-only="true"
rollback-for="Exception" />
<tx:method name="insert*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="modify*" propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="*" read-only="true"
rollback-for="Exception" />
</tx:attributes>
</tx:advice>
。
當在oddtech.service.impl包下某個類(Test)某個方法(insert)使用了@Transactional,相當於在執行new Test().insert() 方法執行2次AOP切面。那麼我們需要通過order 屬性去定義AOP切面的先後執行順序。 order越小,在AOP的chain 中越靠前,越先執行。(chain模式)
,
所以 我們需要在<tx:annotation-driven transaction-manager=”txManager” order=”0”/>中加入order屬性為0,<aop:advisor advice-ref=”txAdvice” pointcut-ref=”txPoint” order=”1”/>加入order 屬性為1.那麼他們兩個的執行順序如下:
。這樣就屬於事務巢狀。
那麼我們再看上邊說的例子:當在oddtech.service.impl包下某個類(Test)某個方法(insert)使用了@Transactional,那麼我們想讓insert 方法只讀,read-only=true,那麼我們需要這樣去定義:@Transactional(readOnly = true,propagation=Propagation.REQUIRED),為什麼呢?
在宣告事務中,我們對insert 的事務傳播級別定義為:REQUIRED,關於事務傳播級別,請參照http://blog.csdn.net/feng27156/article/details/8534609,那麼在註解事務中我們定義REQUIRED 的事務。宣告事務在使用註解定義的事務級別。
除非在特殊的情況下,註解事務不要和宣告事務有衝突。宣告事務定義的是統一的規則,如果你想讓某一個方法有特殊的事務傳播機制的話,那麼不要和統一的規則有衝突。
<tx:method name=”*” read-only=”true” rollback-for=”Exception” />
按照規則,定義一個test方法,加入:@Transactional定義。則test 方法為read-only=false,propagation=REQUIRED。這是預設的。統一規則<tx:method name=”*” read-only=”true” rollback-for=”Exception” />不會對test方法的註解事務衝突。