spring 的優點?
1.降低了組件之間的耦合性 ,實現了軟件各層之間的解耦
2.可以使用容易提供的眾多服務,如事務管理,消息服務等
3.容器提供單例模式支持
4.容器提供了AOP技術,利用它很容易實現如權限攔截,運行期監控等功能
5.容器提供了眾多的輔助類,能加快應用的開發
6.spring對於主流的應用框架提供了集成支持,如hibernate,JPA,Struts等
7.spring屬於低侵入式設計,代碼的污染極低
8.獨立於各種應用服務器
9.spring的DI機制降低了業務對象替換的復雜性
10.Spring的高度開放性,並不強制應用完全依賴於Spring,開發者可以自由選擇spring的部分或全部
什么是DI機制?
依賴注入(Dependecy Injection)和控制反轉(Inversion of Control)是同一個概念,具體的講:當某個角色
需要另外一個角色協助的時候,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例。但在spring中
創建被調用者的工作不再由調用者來完成,因此稱為控制反轉。創建被調用者的工作由spring來完成,然后注入調用者
因此也稱為依賴注入。
spring以動態靈活的方式來管理對象 , 注入的兩種方式,設置注入和構造注入。
設置注入的優點:直觀,自然
構造注入的優點:可以在構造器中決定依賴關系的順序。
什么是AOP?
面向切面編程(AOP)完善spring的依賴注入(DI),面向切面編程在spring中主要表現為兩個方面
1.面向切面編程提供聲明式事務管理
2.spring支持用戶自定義的切面
面向切面編程(aop)是對面向對象編程(oop)的補充,
面向對象編程將程序分解成各個層次的對象,面向切面編程將程序運行過程分解成各個切面。
AOP從程序運行角度考慮程序的結構,提取業務處理過程的切面,oop是靜態的抽象,aop是動態的抽象,
是對應用執行過程中的步驟進行抽象,,從而獲得步驟之間的邏輯划分。
aop框架具有的兩個特征:
1.各個步驟之間的良好隔離性
2.源代碼無關性
Spring @Transactional原理及使用
本文主要討論Spring聲明式事務中使用注解@Transactional的方式、原理及注意事項,主要包括以下內容:
- Spring @Transactional的配置使用;
- Spring @Transactional的傳播行為和隔離級別;
- Spring @Transactional的工作原理;
- Spring @Transactional的注意事項;
- Spring @Transactional自我調用中的問題。
1、Spring @Transactional的配置
步驟一、在Spring配置文件中引入命名空間
1 |
<beans xmlns="http://www.springframework.org/schema/beans" |
步驟二、xml配置文件中,添加事務管理器bean配置
<!-- 事務管理器配置,單數據源事務 -->
<bean id="pkgouTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="pkGouDataSource" />
</bean>
<!-- 使用annotation定義事務 -->
<tx:annotation-driven transaction-manager="pkgouTransactionManager" />
步驟三、在使用事務的方法或者類上添加 @Transactional(“pkgouTransactionManager”)注解
2、 Spring @Transactional的傳播行為和隔離級別
1> 事務注解方式: @Transactional
- 標注在類前:標示類中所有方法都進行事務處理
- 標注在接口、實現類的方法前:標示方法進行事務處理
2> 事務傳播行為介紹:
事務傳播行為 | 說明 |
---|---|
@Transactional(propagation=Propagation.REQUIRED) | 如果有事務, 那么加入事務, 沒有的話新建一個(默認情況) |
@Transactional(propagation=Propagation.NOT_SUPPORTED) | 容器不為這個方法開啟事務 |
@Transactional(propagation=Propagation.REQUIRES_NEW) | 不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務 |
@Transactional(propagation=Propagation.MANDATORY) | 必須在一個已有的事務中執行,否則拋出異常 |
@Transactional(propagation=Propagation.NEVER) | 必須在一個沒有的事務中執行,否則拋出異常(與Propagation.MANDATORY相反) |
@Transactional(propagation=Propagation.SUPPORTS) | 如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務。如果其他bean沒有聲明事務,那就不用事務 |
3> 事務超時設置:
@Transactional(timeout=30) //默認是30秒
4> 事務隔離級別:
事務隔離級別 | 說明 |
---|---|
@Transactional(isolation = Isolation.READ_UNCOMMITTED) | 讀取未提交數據(會出現臟讀, 不可重復讀),基本不使用 |
@Transactional(isolation = Isolation.READ_COMMITTED)(SQLSERVER默認) | 讀取已提交數據(會出現不可重復讀和幻讀) |
@Transactional(isolation = Isolation.REPEATABLE_READ) | 可重復讀(會出現幻讀) |
@Transactional(isolation = Isolation.SERIALIZABLE) | 串行化 |
- 臟讀 : 一個事務讀取到另一事務未提交的更新數據
- 不可重復讀 : 在同一事務中, 多次讀取同一數據返回的結果有所不同, 換句話說, 后續讀取可以讀到另一事務已提交的更新數據。相反,”可重復讀”在同一事務中多次讀取數據時,能夠保證所讀數據一樣,也就是后續讀取不能讀到另一事務已提交的更新數據
- 幻讀 : 一個事務讀到另一個事務已提交的insert數據
@Transactional的屬性:
3、 Spring @Transactional的工作原理
- 自動提交
默認情況下,數據庫處於自動提交模式。每一條語句處於一個單獨的事務中,在這條語句執行完畢時,如果執行成功則隱式的提交事務,如果執行失敗則隱式的回滾事務。
事務管理,是一組相關的操作處於一個事務之中,因此必須關閉數據庫的自動提交模式。這點,Spring會在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中將底層連接的自動提交特性設置為false。
1 |
// switch to manual commit if necessary。 this is very expensive in some jdbc drivers, |
- spring事務回滾規則
Spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。Spring事務管理器會捕捉任何未處理的異常,然后依據規則決定是否回滾拋出異常的事務。
默認配置下,Spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾)。而拋出checked異常則不會導致事務回滾。
Spring也支持明確的配置在拋出哪些異常時回滾事務,包括checked異常。也可以明確定義哪些異常拋出時不回滾事務。
還可以編程性的通過setRollbackOnly()方法來指示一個事務必須回滾,在調用完setRollbackOnly()后你所能執行的唯一操作就是回滾。
在上一篇文章中,我們使用了聲明式事務來配置事務,使事務配置從service邏輯處理中解耦出來。但它還存在一些缺點:
1. 我們只針對方法名的特定進行攔截,但無法利用方法簽名的其它信息定位,如修飾符、返回值、方法入參、異常類型等。如果我們需要為同名不同參的同載方法配置不同事務就會出問題了。
2. 事務屬性的配置串雖然能包含較多信息,但配置較易出錯。
針對這些問題,我們可以基於Schema,引入tx和aop的命名空間來改進我們的配置:
- 引入命名空間
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
- tx\aop核心配置
<!-- 配置事務屬性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRES_NEW" /> <tx:method name="update*" propagation="REQUIRES_NEW" /> <tx:method name="delete*" propagation="REQUIRES_NEW" /> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <!-- 配置事務切入點,以及把事務切入點和事務屬性關聯起來 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.yc.service.*.*(..))" id="ServicePointcut" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="ServicePointcut" /> </aop:config>
這里需要特別注意的是,我們需要在標簽中將proxy-target-class配置成true,否則會出現和上一篇文章相同的錯誤:我們定義的類無法轉換成代理類
這里我們通過來配置我們的事務增強屬性。在標簽中,常見屬性及其說明如下,其中,除了name屬性是必選外,其他都是可選的:
屬性 | 說明 | 默認 | 允許值 |
---|---|---|---|
name | 匹配方法名 | 必須聲明,至少為* | 可使用*通配符 |
propagation | 事務傳播行為 | REQUIRED | REQUIRED,SUPPORTS和MANDATORY和REQUIRES_NEW和NOT_SUPPORTED和NEVER和NESTED |
read-only | 設置當前事務是否只讀 | false | true,false |
isolation | 事務隔離級別 | DEFAULT | READ_UNCOMMITTED和READ_COMMITTED和REPEATABLE_READ和SERIALIZABLE |
timeout | 設置事務的超時時間 | -1 | 默認由頂層事務系統決定 |
rollback-for | 內容為異常名,表示當拋出這些異常時事務回滾,可以用逗號分隔配置多個 | 無默認值 | 可以使用異常名稱的片段進行匹配如ception等 |
no-rollback-for | 內容為異常名,表示當拋出這些異常時繼續提交事務,可以用逗號分隔配置多個 | 無默認值 | 可以使用異常名稱的片段進行匹配如ception等。 |