@Transactional 內(nèi)部調(diào)用例子 ??
在 Spring 的 AOP 代理下,只有目標方法由外部調(diào)用,目標方法才由 Spring 生成的代理對象來管理,這會造成自調(diào)用問題。
若同一類中的其他沒有@Transactional 注解的方法內(nèi)部調(diào)用有@Transactional 注解的方法,有@Transactional 注解的方法的事務被忽略,不會發(fā)生回滾
@Service
public class A{
public void action(){
dosome();
}
@Transactional
public void dosome(){
doa.insert(new Object());
}
}
如上代碼,在方法dosome()中拋出異常時,數(shù)據(jù)操作不會回滾
解決方案
思路: 強制使用 AspectJ 對方法進行切面
Springboot 引入 AspectJ 切面
pom.xml 中添加AspectJ:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
啟動類中添加 @EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class DonngPartsApplication {
public static void main(String[] args) {
SpringApplication.run(DonngPartsApplication.class, args);
}
}
注意: exposeProxy = true 若不添加,則會報:
java.lang.IllegalStateException:
Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available,
and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
代碼中 ((A) AopContext.currentProxy()).dosome()
修改為如下代碼,事務就生效啦
@Service
public class A{
public void action(){
((A) AopContext.currentProxy()).dosome();
}
@Transactional
public void dosome(){
doa.insert(new Object());
}
}
@Transactional 進階
1. @Transactional 注解的屬性信息
| 屬性 | 描述 |
|---|---|
| name | 當在配置文件中有多個 TransactionManager , 可以用該屬性指定選擇哪個事務管理器 |
| propagation | 事務的傳播行為,默認值為 REQUIRED |
| isolation | 事務的隔離度,默認值采用 DEFAULT |
| timeout | 事務的超時時間,默認值為-1。如果超過該時間限制但事務還沒有完成,則自動回滾事務 |
| read-only | 指定事務是否為只讀事務,默認值為 false;為了忽略那些不需要事務的方法,比如讀取數(shù)據(jù),可以設置 read-only 為 true |
| rollback-for | 用于指定能夠觸發(fā)事務回滾的異常類型,如果有多個異常類型需要指定,各類型之間可以通過逗號分隔 |
| no-rollback- for | 拋出 no-rollback-for 指定的異常類型,不回滾事務 |
2. propagation 傳播行為
- REQUIRED:如果有事務, 那么加入事務, 沒有的話新建一個(默認情況下)
- NOT_SUPPORTED:容器不為這個方法開啟事務
- REQUIRES_NEW:不管是否存在事務,都創(chuàng)建一個新的事務,原來的掛起,新的執(zhí)行完畢,繼續(xù)執(zhí)行老的事務
- MANDATORY:必須在一個已有的事務中執(zhí)行,否則拋出異常
- NEVER:必須在一個沒有的事務中執(zhí)行,否則拋出異常(與MANDATORY相反)
- SUPPORTS:如果其他bean調(diào)用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.
- NESTED: 如果當前存在事務,則在嵌套事務內(nèi)執(zhí)行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。
3. 事物超時設置
@Transactional(timeout=30) //默認是30秒
4. 事務隔離級別 isolation
- READ_UNCOMMITTED:讀取未提交數(shù)據(jù)(會出現(xiàn)臟讀, 不可重復讀) 基本不使用
- READ_COMMITTED:讀取已提交數(shù)據(jù)(會出現(xiàn)不可重復讀和幻讀)
- REPEATABLE_READ:可重復讀(會出現(xiàn)幻讀)
- SERIALIZABLE:串行化
注意
@Transactional 只能被應用到public方法上
僅僅 @Transactional 注解的出現(xiàn)不足于開啟事務行為,它僅僅 是一種元數(shù)據(jù)
收工 !!!
更多好玩好看的內(nèi)容,歡迎到我的博客交流,共同進步????????WaterMin