原文引自 http://express.ruanko.com/ruanko-express_42/tech-overnight2.htmlhtml
每次帶班,講到Spring事務這一塊的時候,你們老是有不少的疑問,其實Spring事務並不難,可能初次接觸的時候有的很差理解,今天咱們就詳細來談一下Spring的事務管理機制,主要是對Hibernate進行的事務管理。spring
在談Spring事務管理以前咱們想一下在咱們不用Spring的時候,在Hibernate中咱們是怎麼進行數據操做的。在Hibernate中咱們每次進行一個操做的的時候咱們都是要先開啓事務,而後進行數據操做,而後提交事務,關閉事務,咱們這樣作的緣由是由於Hibernate默認的事務自動提交是false,他是須要咱們人爲的手動提交事務,假如你不想每次都手動提交事務的話,你能夠在hibernate.cfg.xml我文件中把它設置爲事務自動提交:express
<property name="hibernate.connection.autocommit">true</property>
當咱們Spring對咱們的Hibernate進行整合以後,咱們的代碼又出現了什麼變化呢?整合,以後,咱們再也不是每次都去拿Session進行數據操做了,也不須要每次都開啓事務,提交事務了,咱們只須要Spring給咱們提供的一個HibernateTemplate,咱們直接用這個類裏面給咱們提供的數據操做方法就能夠操做數據了。咱們在也看不到關於事務的代碼了,那Spring究竟有沒有在他的操做方法裏面封裝事務處理呢?有的人直接HibernateTemplate裏面提供的方法操做數據,成功了,有的人卻又失敗了,這究竟是怎麼回事呢?其實這裏要看咱們是怎樣集成咱們的Hibernate和Spring,若是在集成的過程當中,咱們拋棄了hibernate.cfg.xml文件,直接在Spring的的配置文件中進行配置數據源的話,那你直接用HibernateTemplate裏面提供的方法是能夠成功操做數據的,若是你仍是用hibernate.cfg.xml來配置數據源,在Spring的配置文件中引用hibernate.cfg.xml文件,那麼你不能成功,這其中的緣由就是由於若是你用 hibernate.cfg.xml文件配置數據源,就像咱們前面說的,Hibernate默認是手動提交事務,而HibernateTemplatel提供的方法裏面並無提供事務提交,而若是你用Spring的配置文件來配置數據源,Sping默認是自動提交的,因此就會成功,若是你想把Spring設置爲手動提交你能夠在起配置文件中進行配置:編程
<property name="defaultAutoCommit"> <value>false</value></property>
縱然咱們把它的事務提交方式設置爲自動,它能夠進行數據操做,可是這樣並不知足咱們實際的業務需求,由於有時候在我保存一個數據以後,我但願他能繼續保存另外一條數據,我但願在保存完兩條或者多條以後一塊兒進行事務提交,這樣即便出錯,咱們能夠回滾,取保數據的一致性,要麼都成功要麼都失敗,這時候咱們就不能每保存完一條數據以後事務就自動提交,由於這樣它們不在同一個事務當中,咱們不能保證數據的一致行。因此這時候咱們就須要手動的來配置咱們的事務,這就須要用到Spring爲Hibernate提供的事務管理機制,Spring提供的事務管理能夠分爲兩類:編程式的和聲明式的,編程式,其實就是在代碼裏面來控制,像Hibernate操做數據同樣,開啓事務,提交事務,這種方式有必定的侷限性,因此咱們通常是用聲明式來配置咱們的事務。緩存
聲明式事務配置主要分如下幾步:session
一、聲明式事務配置spa
配置事務管理器;hibernate
事務的傳播特性;code
那些類那些方法使用事務。orm
<!-- 配置事務管理器 指定其做用的sessionFactory把事務交給Spring去處理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean><!-- 配置事務的傳播特性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice><!-- 那些類的哪些方法參與事務 --> <aop:config> <aop:pointcut id="allServiceMethod" expression="execution(* com.coe.service.*.*(..))"/> <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice"/> </aop:config>
咱們在配置事務的時候,咱們通常是把事務邊界設置到service層,也就是你的業務邏輯層,由於咱們不少時候都是在咱們的業務邏輯層來完成咱們一些列的數據操做,若是放到Dao數據層,其粒度過小了。另外,若是咱們把事務配置在業務邏輯層的話,對咱們的二級緩存也是有好處的,這個你們之後實際操做的時候會發現。
二、編寫業務邏輯方法
這時候咱們就能夠在咱們業務邏輯層用HibernateTemplate裏面提供的數據操做方法來編寫咱們的業務邏輯方法了,固然咱們的方法必需要是以咱們事務配置裏面配置的同樣,用save,delete,update,get作咱們的方法的開頭。須要注意的是,默認狀況下運行期異常纔會回滾(包括繼承了RuntimeException子類),普通異常是不會滾的。
最後咱們順便總結一下事務的幾種傳播特性:
1. PROPAGATION_REQUIRED: 若是存在一個事務,則支持當前事務。若是沒有事務則開啓;
2. PROPAGATION_SUPPORTS: 若是存在一個事務,支持當前事務。若是沒有事務,則非事務的執行;
3. PROPAGATION_MANDATORY: 若是已經存在一個事務,支持當前事務。若是沒有一個活動的事務,則拋出異常;
4. PROPAGATION_REQUIRES_NEW: 老是開啓一個新的事務。若是一個事務已經存在,則將這個存在的事務掛起;
5. PROPAGATION_NOT_SUPPORTED: 老是非事務地執行,並掛起任何存在的事務;
6. PROPAGATION_NEVER: 老是非事務地執行,若是存在一個活動事務,則拋出異常;
7. PROPAGATION_NESTED:若是一個活動的事務存在,則運行在一個嵌套的事務中. 若是沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行。