1. 程式人生 > >Spring宣告式事務(待更新)

Spring宣告式事務(待更新)

四大特性:ACID

原子性:一個事務必須視為一個不可分割的最小工作單元,一個事務要麼全部完成,要麼全部失敗回滾,不可能只執行其中的一部分操作

  • 一致性:事務執行的結果必須使資料庫從一個一致性狀態轉換到另一個一致性狀態,事務必須使資料庫始終保持一致性狀態
  • 隔離性isolation:併發執行的事務之間彼此無法看到對方的中間狀態
  • 永續性:事務完成後所做的改動會持久化到資料庫中

如果不考慮隔離性的話,高併發事務可能會出現的問題:

  • 髒讀 :事務A讀取到事務B未提交成功的資料
  • 不可重複讀 :事務A讀取到事務B提交的update後的資料,導致前後查詢不一致
  • 幻讀:事務A讀取到事務B提交的insert資料,導致前後資料查詢不一致

五大隔離級別(√可能發生×不可能發生)

其中一個為default預設採用資料庫預設隔離級別
mysql預設是Reptable Read可重複讀
sqlServer,Oracle是Read Committed讀已提交

隔離級別 髒讀 不可重複讀 幻讀
Read Uncommitted(讀未提交)
Read Committed(讀已提交) ×
Reptable Read(可重複讀) × ×
Serilizable (序列) × × ×

七大傳播機制

Propagation:事務傳播機制,該屬性的可選值如下

  1. required:支援當前事務,如果有就加入當前事務,如果當前方法沒有事務,就新建一個事務,預設事務傳播機制
  2. supports:支援當前事務,如果有就加入當前事務,如果當前方法沒有事務,就以非事務的方式執行
  3. manatory:支援當前事務
    ,如果有就加入當前事務,如果當前方法沒有事務,就丟擲異常,與never相反
  4. requires_new:新建事務,如果當前存在事務,就把當前事務掛起,如果當前方法沒有事務,就新建事務
  5. not supported:以非事務方式執行,如果當前方法存在事務就掛起當前事務,如果當前方法不存在事務,就以非事務方式執行
  6. never:總是以非事務方法執行,如果當前方法存在事務就丟擲異常,與manatory相反
  7. nested:如果當前方法有事務,則在巢狀事務內執行;如果當前方法沒有事務,則與required操作類似,也就是新建一個事務

具體使用如下

1.xml配置

1.依賴

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.13</version>
</dependency>

2.spring配置檔案

<!--配置事務管理器元件,注入事先定義好的資料來源元件-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!--為指定的事務管理器設定事務屬性-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--定義屬性,宣告規則-->
    <tx:attributes>
        <tx:method name="find*" propagation="SUPPORTS"/>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="del*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--定義切面-->
<aop:config>
    <!--定義切入點-->
    <aop:pointcut id="serviceMethod" expression="execution(* cn.yinjian.curd.service..*.*(..))"/>
    <!--將事務增強與切入點結合-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>

2.註解方式

@Transactional
spring配置檔案

<!--配置事務管理器元件-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   	<property name="dataSource" ref="dataSource"></property>
</bean>
<!--新增對註解事務的支援-->
<tx:annotation-driven transaction-manager="transactionManager"/>

@Transactional
預設設定:
事務傳播設定是required
事務隔離級別是default
事務是讀/寫
事務超時預設是依賴於事務系統的,或者不支援事務超時
任何RuntimeException將觸發事務回滾,但是任何checked Exception不會觸發事務回滾

面試題:spring 事物 關於在同一個類中一個方法呼叫另一個方法,事物的傳播行為會失效

解決方法1:

將事務方法放到另一個類中(或者單獨開啟一層,取名“事務層”)進行呼叫,即符合了在物件之間呼叫的條件。

解決方法2:

獲取本物件的代理物件,再進行呼叫。具體操作如:

  1. Spring-content.xml上下文中,增加配置:<aop:aspectj-autoproxy expose-proxy=“true”/>

  2. 在xxxServiceImpl中,用(xxxService)(AopContext.currentProxy()),獲取到xxxService的代理類,再呼叫事務方法,強行經過代理類,啟用事務切面。

解決方法3:

很多時候,方法內呼叫又希望啟用事務,是由於同一個方法既有DAO操作又有I/O等耗時操作,不想讓耗時的I/O造成事務的太長耗時(比如新增商品同時需要寫入庫存)。此時,可以將I/O做成非同步操作(如加入執行緒池),而加入執行緒池的操作即便加入事務也不會導致事務太長,問題可以迎刃而解。