1、Spring事务
1.1 Spring事务介绍
事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性。
1.1.1 事务的四大特性(ACID)
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中
1.1.2 Spring支持的事务类型
- 编程式事务(编码式事务)
- 指的是将事务管理代码嵌入业务方法中来控制事务的提交和回滚,必须在每个业务操作中包含额外的事务管理代码。
- 声明式事务
- 指的是将事务管理代码从业务方法中分离出来,以声明的方式来实现事务的管理。
1.1.3 Spring的事务管理器
- DataSourceTransactionManager:使用Spring JDBC或iBatis进行持久化数据时使用
- JdoTransactionManager:使用Hibernate持久化数据时使用
- JpaTransactionManager:当持久化机制时Jdo时使用
- HibernaTransactionManager:使用一个JTA实现来管理事务,在一个事务跨多个资源时必须使用
1.2 Spring声明式事务
比较常用的就是使用@Transactional注解在类或者方法中表明该类或者方法需要事务支持。
1.3 Spring注解事务行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
1.3.1 传播行为
传播行为 含义 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务;如果已经存在一个事务,就加入这个事务 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行 PROPAGATION_MANDATORY 使用当前的事务,如果当前米有事务,就抛出异常 PROPAGATIONREQUIREDNEW 新建事务,如果当前存在事务,就把当前事务挂起 PROPAGATIONNOTSUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,就抛出异常 PROPAGATION_NESTED 如果当前存在事务,就在嵌套事务内执行,如果当前没有事务,就执行与PROPAGATION_REQUIRED类似的操作 1.3.2 隔离级别
隔离级别
场景 脏读(Dirty Read) 一个事务读取了另一个事务改写但未提交的数据,如果改后被回滚了,那么第一个事务获取的数据是无效 不可重复读(Nonrepeatable Read) 一个事务执行相同的查询俩次或者俩次以上,但每次都得到不同的数据,因为另一个事务在俩次查询期间更新了数据 幻读(Phantom Read) 与不可重复读类似,事务T1读取了几行数据,T2事务插入了一些数据。然后之后的查询中T1会多了原本不存在的数据 2、SpringBoot事务的使用
2.1 类级别事务
@Transactional注解在类上,表示此类的所有public方法都是开启事务
2.2 方法级别事务
@Transactional注解在方法上,如果类和方法同时使用了@Transactional注解,就使用方法级别注解覆盖类级别注解
2.3 @Transactional源码分析
package org.springframework.transaction.annotation;@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD})@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)@java.lang.annotation.Inherited@java.lang.annotation.Documentedpublic @interface Transactional { // 通过bean name指定事务管理器 @org.springframework.core.annotation.AliasFor("transactionManager") java.lang.String value() default ""; // 同value属性 @org.springframework.core.annotation.AliasFor("value") java.lang.String transactionManager() default ""; // 指定传播行为 org.springframework.transaction.annotation.Propagation propagation() default org.springframework.transaction.annotation.Propagation.REQUIRED; // 指定隔离级别 org.springframework.transaction.annotation.Isolation isolation() default org.springframework.transaction.annotation.Isolation.DEFAULT; // 超时时间,单位秒 int timeout() default -1; // 是否是只读事务 boolean readOnly() default false; // 方法上发生指定异常时回滚,默认是所有异常都回滚 java.lang.Class extends java.lang.Throwable>[] rollbackFor() default {}; // 方法上发生指定异常名时回滚,默认是所有异常都回滚 java.lang.String[] rollbackForClassName() default {}; // 方法在发生指定异常时不回滚,默认所有异常都回滚 java.lang.Class extends java.lang.Throwable>[] noRollbackFor() default {}; // 方法在发生指定异常名称时不回滚,默认是所有异常都回滚 java.lang.String[] noRollbackForClassName() default {};}
3、测试数据库事务
代码清单3-1 SQL脚本
DROP TABLE IF EXISTS `t_user`;CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID', `name` varchar(10) DEFAULT '' COMMENT '用户姓名', `password` varchar(32) DEFAULT '' COMMENT '密码', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;INSERT INTO `t_user` VALUES (1, '小H', '123456');INSERT INTO `t_user` VALUES (2, '萧炎', '123456');
代码清单3-2 用户实体类
public class User { // 主键 private String id; // 用户名 private String name; // 密码 private String password; //省略getter、setter、toString方法}
代码清单3-3 MyBatis接口文件
@Mapperpublic interface UserDao { List findAll(); Long save(User user);}
代码清单3-4 用户映射文件
<?xml version="1.0" encoding="UTF-8"?> id, name, password SELECT FROM t_user insert into t_user(name, password) value(#{name}, #{password})
代码清单3-5 用户服务接口及实现类
public interface UserService { List findAll(); Long save(User user);}@Servicepublic class UserServiceImpl implements UserService { @Autowired UserDao userDao; /** * 开启事务,采用读写提交的隔离级别,超时时间设置为1s * @return */ @Override @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 1) public List findAll() { return userDao.findAll(); } /** * 开启事务,采用读写提交的隔离级别,超时时间设置为1s * @return * */ @Override @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 1) public Long save(User user) { return userDao.save(user); }}
代码清单3-6 controller测试数据库事务
@RestControllerpublic class UserController { @Autowired private UserService userService; @RequestMapping(value = "/users") public List findAll() { return userService.findAll(); } @RequestMapping(value = "/add") public List save(String name, String password) { User user = new User(); user.setName(name); user.setPassword(password); Long userId = userService.save(user); return userService.findAll(); }}
代码清单3-7 配置文件
spring: datasource: url: jdbc:mysql://172.16.6.31:3306/test username: root password: 123456 tomcat: max-idle: 10 max-active: 50 max-wait: 10000 initial-size: 5 driver-class-name: com.mysql.jdbc.Driverlogging: level: root: debug org: springframwwork: debug org: mybatis: debugmybatis: mapper-locations: classpath*:/mapper/*Mapper.xml type-aliases-package: com.xiaoh.springboot.transaction.domain
代码清单 3-8 启动类
@SpringBootApplication@MapperScan(value = "com.xiaoh.springboot.transaction.dao")public class SpringbootTransactionApplication { public static void main(String[] args) { SpringApplication.run(SpringbootTransactionApplication.class, args); } }
启动项目,在浏览器中输入:http://localhost:8080/add?name=萧力&password=123456 ,可以看到控制台打印的日志:
![282e0ba5-1113-eb11-8da9-e4434bdf6706.png](http://p01.5ceimg.com/content/282e0ba5-1113-eb11-8da9-e4434bdf6706.png)
从日志中可以看到Spring获取了数据库连接以及修改了隔离级别,然后在执行SQL,在最后会自动地关闭和提交数据库事务,Spring会把标注了@Transactional的方法的代码织入约定的事务流程中。
本文由博客一文多发平台 https://openwrite.cn?from=article_bottom 发布!