Spring事务
2023-12-14 00:27:34
为什么需要事务
什么是事务
将一组操作封装成一个执行单元,要么全部执行,要么全部不执行
为什么需要事务
例如转账场景,张三有1000块,给李四转500,张三账户-500;李四账户+500.如果没有事务,可能张三扣款执行了,李四加钱操作没执行。而使用事务可以保证转账操作要么一起执行,要么不执行
Spring中事务的实现
1.通过代码方式手动实现事务
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private DataSourceTransactionManager transactionManager;//用来管理事务
@Autowired
private TransactionDefinition transactionDefinition;//设置事务属性
@RequestMapping("/add")
public int add(Userinfo userinfo) {
//非空校验
if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())
|| !StringUtils.hasLength(userinfo.getPassword())) {
return 0;
}
//开启事务,需要传事务的属性
TransactionStatus transactionStatus = transactionManager
.getTransaction(transactionDefinition);
//手动设置时间
userinfo.setCreatetime(LocalDateTime.now().toString());
userinfo.setUpdatetime(LocalDateTime.now().toString());
int result = userService.add(userinfo);
System.out.println("添加:" + result);
transactionManager.rollback(transactionStatus);//传要回滚哪个事务
//提交事务
//transactionManager.commit(transactionStatus);
return result;
}
}
2.通过注解方式实现声明事务、
只需要在方法上或类上添加@Transacational注解即可(修饰方法时只能作用于public方法,修饰类时,类里面所有publice方法都生效),无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完成后自动提交事务,如果中途有被JVM捕捉到异常会自动回滚事务
//使用@Transactional声明事务
@RequestMapping("/insert")
@Transactional
public int insert(Userinfo userinfo) {
if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())
|| !StringUtils.hasLength(userinfo.getPassword())) {
return 0;
}
int result = userService.add(userinfo);
//int num = 10 / 0; 发生算数异常,会自动回滚
return result;
}
注意:当程序有try-catch之后,即使程序发送异常,事务也不会自动回滚
解决方案有两种
- 将异常抛出
//使用@Transactional声明事务
@RequestMapping("/insert")
@Transactional
public int insert(Userinfo userinfo) {
if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())
|| !StringUtils.hasLength(userinfo.getPassword())) {
return 0;
}
int result = userService.add(userinfo);
try {
int num = 10 / 0;
} catch (Exception e) {
throw e;//把异常抛给Jvm让它来处理
}
return result;
}
- 使用代码手段回滚事务
@RequestMapping("/insert")
@Transactional
public int insert(Userinfo userinfo) {
if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())
|| !StringUtils.hasLength(userinfo.getPassword())) {
return 0;
}
int result = userService.add(userinfo);
try {
int num = 10 / 0;
} catch (Exception e) {
//使用代码手动回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
@Transactional工作原理
Transactional是基于AOP思想实现的,AOP又是基于动态代理实现的。如果目标对象实现了接口,默认情况下采用JDK的动态代理;如果目标对象没实现接口,会使用CGLIB动态代理。
Spring事务的隔离级别
- @Transactional(isolation=Isolation.DEFAULT) :以连接的数据库的事务隔离级别为主
- @Transactional(isolation=Isolation.READ_UNCOMMITTED):读未提交,可以读取未提交的事务,存在脏读问题。
- @Transactional(isolation=Isolation.READ_COMMITTED):读以提交,只能读已提交的事务,解决了脏读,但存在不可重复读问题(两次读取到的数据可能不同)
- @Transactional(isolation=Isolation.REPEATABLE_READ):可重复读,解决了不可重复读问题,但存在幻读(一次事务两次查询得到的结果集不同,因为在两次查询中另一个事务新增了一部分数据)
- @Transactional(isolation=Isolation.SERIALIZABLE):解决所有并发问题,但是性能过低。
事务的传播机制
事务的隔离级别解决的是多个事务同时调用数据库的问题,而事务的传播机制解决的是一个事务在多个节点(方法)中传递的问题。
Spring事务的7种传播机制
以默认的传播机制举例:
@RequestMapping("/insert")
@Transactional(propagation = Propagation.REQUIRED)//设置事务传播机制
public int insert(Userinfo userinfo) {
if(userinfo == null || !StringUtils.hasLength(userinfo.getUsername())
|| !StringUtils.hasLength(userinfo.getPassword())) {
return 0;
}
int result = userService.add(userinfo);//插入一条记录
//说明数据已经插入成功
if(result > 0) {
logService.add();
}
return result;
}
@Service
public class LogService {
//如果有事务就加入事务,不存在就创建事务
@Transactional(propagation = Propagation.REQUIRED)
public int add() {
try {
int num = 10 / 0;
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return 1;
}
}
Controller层和Service层都设置了事务的传播机制为:如果有事务就加入事务,没有事务就创建事务。Controller层调用Service层,Controlller层有事务,所以Service层就加入它,变成一个整体,LogService抛出算术异常,整个事务都要回滚,导致原本已经插入成功的记录也要回滚。
文章来源:https://blog.csdn.net/weixin_61427900/article/details/134909167
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!