一:概述及目录
这篇源码解析,和 Spring AOP 中的知识有很多重合的地⽅,但是⽐ AOP 要稍微简单⼀些,建议两篇⽂章对⽐学 习。
下⾯我会简单介绍⼀下 Spring 事务的基础知识,以及使⽤⽅法,然后直接对源码进⾏拆解。
目录:
二. 项⽬准备
下⾯是 DB 数据和 DB 操作接⼝:
Id | uname | usex |
---|---|---|
1 | 小王 | 男 |
2 | 小李 | 女 |
1 | 小赵 | 男 |
@Data
public class MyUser {
private int id;
private String uname;
private String usex;
}
复制代码
public interface UserDao {
// select * from user_test where id = "#{id}"
MyUser selectUserById(Integer uid);
// update user_test set uname =#{uname},usex = #{usex} where id = #{id}
int updateUser(MyUser user);
}
复制代码
基础测试代码,testSuccess() 是事务⽣效的情况:
@Service
public class Model {
@Autowired
private UserDao userDao;
public void update(Integer id) {
MyUser user = new MyUser();
user.setId(id);
user.setUname("张三-testing");
user.setUsex("⼥");
userDao.updateUser(user);
}
public MyUser query(Integer id) {
MyUser user = userDao.selectUserById(id);
return user;
}
// 正常情况
@Transactional(rollbackFor = Exception.class)
public void testSuccess() throws Exception {
Integer id = 1;
MyUser user = query(id);
System.out.println("原记录:" + user);
update(id);
throw new Exception("事务⽣效");
}
}
复制代码
执⾏⼊⼝:
public class SpringMyBatisTest {
public static void main(String[] args) throws Exception {
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext(xmlPath);
Model uc = (Model) applicationContext.getBean("model");
uc.testSuccess();
}
}
复制代码
输出:
三:Spring 事务⼯作流程
为了⽅便⼤家能更好看懂后⾯的源码,我先整体介绍⼀下源码的执⾏流程,让⼤家有⼀个整体的认识,否则容易被 绕进去。
整个 Spring 事务源码,其实分为 2 块,我们会结合上⾯的示例,给⼤家进⾏讲解。
第⼀块是后置处理,我们在创建 Model Bean 的后置处理器中,⾥⾯会做两件事情:
获取 Model 的切⾯⽅法:⾸先会拿到所有的切⾯信息,和 Model 的所有⽅法进⾏匹配,然后找到 Model 所有需 要进⾏事务处理的⽅法,匹配成功的⽅法,还需要将事务属性保存到缓存 attributeCache 中。
创建 AOP 代理对象:结合 Model 需要进⾏ AOP 的⽅法,选择 Cglib 或 JDK,创建 AOP 代理对象。
第⼆块是事务执⾏,整个逻辑⽐较复杂,我只选取 4 块最核⼼的逻辑,分别为从缓存拿到事务属性、创建并开启事 务、执⾏业务逻辑、提交或者回滚事务。
四. 源码解读
注意:Spring 的版本是 5.2.15.RELEASE,否则和我的代码不⼀样!!