成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring事務的這十種坑,坑坑致命!

開發 后端
spring事務大多數情況下,可以滿足我們的業務需求。但是今天我要告訴大家的是,它有很多坑,稍不注意事務就會失效。

 

1.錯誤的訪問權限

@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
private void add(UserModel userModel) {
userMapper.insertUser(userModel);
}
}

我們可以看到add方法的訪問權限被定義成了private,這樣會導致事務失效,spring要求被代理方法必須是public的。

AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法中有個判斷,如果目標方法不是public,則TransactionAttribute返回null,即不支持事務。

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}

2.方法被定義成final的

@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public final void add(UserModel userModel) {
userMapper.insertUser(userModel);
}
}

我們可以看到add方法被定義成了final的,這樣會導致spring aop生成的代理對象不能復寫該方法,而讓事務失效。

3.方法內部調用

@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void add(UserModel userModel) {
userMapper.insertUser(userModel);
updateStatus(userModel);
}
@Transactional
public void updateStatus(UserModel userModel) {
// doSameThing();
}
}

我們看到在事務方法add中,直接調用事務方法updateStatus。從前面介紹的內容可以知道,updateStatus方法擁有事務的能力是因為spring aop生成代理了對象,但是這種方法直接調用了this對象的方法,所以updateStatus方法不會生成事務。

 4.當前實體沒有被spring管理

//@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void add(UserModel userModel) {
userMapper.insertUser(userModel);
}
}

我們可以看到UserService類沒有定義@Service注解,即沒有交給spring管理bean實例,所以它的add方法也不會生成事務。

 5.錯誤的spring事務傳播特性

@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional(propagation = Propagation.NEVER)
public void add(UserModel userModel) {
userMapper.insertUser(userModel);
}
}

我們可以看到add方法的事務傳播特性定義成了Propagation.NEVER,這種類型的傳播特性不支持事務,如果有事務則會拋異常。只有這三種傳播特性才會創建新事務:PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED。

6.數據庫不支持事務

msql8以前的版本數據庫引擎是支持myslam和innerdb的。我以前也用過,對應查多寫少的單表操作,可能會把表的數據庫引擎定義成myslam,這樣可以提升查詢效率。但是,要千萬記得一件事情,myslam只支持表鎖,并且不支持事務。所以,對這類表的寫入操作事務會失效。

7.自己吞掉了異常

@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void add(UserModel userModel) {
try {
userMapper.insertUser(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

這種情況下事務不會回滾,因為開發者自己捕獲了異常,又沒有拋出。事務的AOP無法捕獲異常,導致即使出現了異常,事務也不會回滾。

8.拋出的異常不正確

@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void add(UserModel userModel) throws Exception {
try {
userMapper.insertUser(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new Exception(e);
}
}
}

這種情況下,開發人員自己捕獲了異常,又拋出了異常:Exception,事務也不會回滾。因為spring事務,默認情況下只會回滾RuntimeException(運行時異常)和Error(錯誤),不會回滾Exception。

9.多線程調用

@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleService roleService;
@Transactional
public void add(UserModel userModel) throws Exception {
userMapper.insertUser(userModel);
new Thread(() -> {
roleService.doOtherThing();
}).start();
}
}
@Service
public class RoleService {
@Transactional
public void doOtherThing() {
System.out.println("保存role表數據");
}
}

我們可以看到事務方法add中,調用了事務方法doOtherThing,但是事務方法doOtherThing是在另外一個線程中調用的,這樣會導致兩個事務方法不在同一個線程中,獲取到的數據庫連接不一樣,從而是兩個不同的事務。如果想doOtherThing方法中拋了異常,add方法也回滾是不可能的。

如果看過spring事務源碼的朋友,可能會知道spring的事務是通過數據庫連接來實現的。當前線程中保存了一個map,key是數據源,value是數據庫連接。

private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");

我們說的同一個事務,其實是指同一個數據庫連接,只有擁有同一個數據庫連接才能同時提交和回滾。如果在不同的線程,拿到的數據庫連接肯定是不一樣的,所以是不同的事務。

10.嵌套事務多回滾了

public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleService roleService;
@Transactional
public void add(UserModel userModel) throws Exception {
userMapper.insertUser(userModel);
roleService.doOtherThing();
}
}
@Service
public class RoleService {
@Transactional(propagation = Propagation.NESTED)
public void doOtherThing() {
System.out.println("保存role表數據");
}
}

這種情況使用了嵌套的內部事務,原本是希望調用roleService.doOtherThing方法時,如果出現了異常,只回滾doOtherThing方法里的內容,不回滾 userMapper.insertUser里的內容,即回滾保存點。。但事實是,insertUser也回滾了。

why?

因為doOtherThing方法出現了異常,沒有手動捕獲,會繼續往上拋,到外層add方法的代理方法中捕獲了異常。所以,這種情況是直接回滾了整個事務,不只回滾單個保存點。

怎么樣才能只回滾保存點呢?

@Slf4j
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleService roleService;
@Transactional
public void add(UserModel userModel) throws Exception {
userMapper.insertUser(userModel);
try {
roleService.doOtherThing();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

在代碼中手動把內部嵌套事務放在try/catch中,并且不繼續往拋異常。

介紹到這里,你會發現spring事務的坑還是挺多的~

責任編輯:龐桂玉 來源: Java后端技術
相關推薦

2018-04-02 07:32:15

2021-07-05 05:35:05

道路管理物聯網IOT

2024-09-18 00:00:10

UUID識別碼標志符

2022-01-09 18:32:03

MySQL SQL 語句數據庫

2023-12-13 13:41:00

代碼Java程序員

2022-03-08 09:00:00

Kubernetes容器技術

2024-11-13 00:57:36

2015-10-26 09:38:23

程序員工作

2025-06-16 08:22:23

2019-06-24 15:30:23

編程程序員前景

2024-11-13 13:20:44

2023-05-15 15:29:13

設計模式JavaScript

2024-01-22 08:15:42

API協議設計

2023-05-15 20:08:04

Linux字體

2010-08-30 16:18:05

2020-08-13 07:00:00

工具技術管理

2018-09-25 23:21:13

2010-09-13 17:17:04

2024-08-22 08:54:40

2010-07-07 11:30:16

UML十種圖
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人一区二区 | 综合久久综合久久 | 亚洲美女在线视频 | 天天玩天天操天天干 | 成人国产精品久久久 | 成人免费看片 | 日本成人午夜影院 | 97在线观视频免费观看 | 黄色片亚洲 | 欧美区在线 | 中文字幕日韩三级 | 免费在线一区二区 | 色婷婷av久久久久久久 | 午夜爽爽男女免费观看hd | 久久三区| 色欧美片视频在线观看 | www.亚洲一区 | 日韩午夜 | www.蜜桃av | 日本不卡一区 | 国产欧美日韩综合精品一区二区 | 九九99九九精彩46 | 台湾佬成人网 | 一级大片 | 亚洲黄色一级毛片 | 精品免费国产一区二区三区四区介绍 | 一区二区三区四区av | 视频在线一区二区 | 亚洲欧美国产视频 | 91精品国产乱码麻豆白嫩 | 日本成人三级电影 | 国产一区欧美 | 国产男女精品 | 天天草天天干 | 爱爱免费视频 | 免费黄色av网站 | 人人性人人性碰国产 | 欧美999| 精品在线视频播放 | 中文字幕一区二区三区乱码在线 | 国产精品高潮呻吟久久久久 |