Spring Boot系列 Spring Boot事务应用详解,佳能相机系列详解
墨初 知识笔记 41阅读
public class MainConfig4 {}
当spring容器启动的时候发现有EnableTransactionManagement注解此时会拦截所有bean的创建扫描看一下bean上是否有Transaction注解类、或者父类、或者接口、或者方法中有这个注解都可以如果有这个注解spring会通过aop的方式给bean生成代理对象代理对象中会增加一个拦截器拦截器会拦截bean中public方法执行会在方法执行之前启动事务方法执行完毕之后提交或者回滚事务。

EnableTransactionManagement 的源码
Target(ElementType.TYPE)Retention(RetentionPolicy.RUNTIME)DocumentedImport(TransactionManagementConfigurationSelector.class)public interface EnableTransactionManagement { /** * spring是通过aop的方式对bean创建代理对象来实现事务管理的 * 创建代理对象有2种方式jdk动态代理和cglib代理 * proxyTargetClass为true的时候就是强制使用cglib来创建代理 */ boolean proxyTargetClass() default false; /** * 用来指定事务拦截器的顺序 * 我们知道一个方法上可以添加很多拦截器拦截器是可以指定顺序的 * 比如你可以自定义一些拦截器放在事务拦截器之前或者之后执行就可以通过order来控制 */ int order() default Ordered.LOWEST_PRECEDENCE;}
2. 定义事务管理器 事务交给spring管理那么你肯定要创建一个或者多个事务管理者有这些管理者来管理具体的事务比如启动事务、提交事务、回滚事务这些都是管理者来负责的。

spring中使用PlatformTransactionManager这个接口来表示事务管理者。
PlatformTransactionManager多个实现类用来应对不同的环境
JpaTransactionManager 如果你用jpa来操作db那么需要用这个管理器来帮你控制事务。
DataSourceTransactionManager 如果你用是指定数据源的方式比如操作数据库用的是JdbcTemplate、mybatis、ibatis那么需要用这个管理器来帮你控制事务。
HibernateTransactionManager 如果你用hibernate来操作db那么需要用这个管理器来帮你控制事务。
JtaTransactionManager 如果你用的是java中的jta来操作db这种通常是分布式事务此时需要用这种管理器来控制事务。
3. 需使用事务的目标上加Transaction注解 Transaction放在接口上那么接口的实现类中所有public都被spring自动加上事务。Transaction放在类上那么当前类以及其下无限级子类中所有pubilc方法将被spring自动加上事务。Transaction放在public方法上那么该方法将被spring自动加上事务。Transaction参数介绍
在Transaction标注类或者目标方法上执行业务操作此时这些方法会自动被spring进行事务管理。
Componentpublic class UserService { Autowired private JdbcTemplate jdbcTemplate; Transactional public void insertBatch(String names) { jdbcTemplate.update(truncate table t_user); for (String name : names) { jdbcTemplate.update(INSERT INTO t_user(name) VALUES (?), name); } }}
5. 启动spring容器使用bean执行业务操作 Testpublic void test1() { AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(); context.register(MainConfig4.class); context.refresh(); UserService userService context.getBean(UserService.class); userService.insertBatch(java高并发系列, mysql系列, maven系列, mybatis系列);}
四、Spring编程式事务 通过硬编码的方式使用spring中提供的事务相关的类来控制事务。
编程式事务主要的两种用法
通过PlatformTransactionManager控制事务。通过TransactionTemplate控制事务。 4.1 PlatfornTransactionManager这种是最原始的方式代码量较大后面其他方式都是针对这种方式的封装
Test public void test1() throws Exception { //定义一个数据源 DataSource dataSource new DataSource(); dataSource.setDriverClassName(com.mysql.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/int?characterEncodingUTF-8&serverTimezoneUTC); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); //定义一个JdbcTemplate用来方便执行数据库增删改查 JdbcTemplate jdbcTemplate new JdbcTemplate(dataSource); //1.定义事务管理器给其指定一个数据源可以把事务管理器想象为一个人这个人来负责事务的控制操作 PlatformTransactionManager platformTransactionManager new DataSourceTransactionManager(dataSource); //2.定义事务属性TransactionDefinition // TransactionDefinition可以用来配置事务的属性信息比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。 TransactionDefinition transactionDefinition new DefaultTransactionDefinition(); //3.开启事务调用platformTransactionManager.getTransaction开启事务操作得到事务状态(TransactionStatus)对象 TransactionStatus transactionStatus platformTransactionManager.getTransaction(transactionDefinition); //4.执行业务操作下面就执行2个插入操作 try { System.out.println(before: jdbcTemplate.queryForList(SELECT * from t_user)); jdbcTemplate.update(insert into t_user (name) values (?), test1-1); jdbcTemplate.update(insert into t_user (name) values (?), test1-2); //5.提交事务platformTransactionManager.commit platformTransactionManager.commit(transactionStatus); } catch (Exception e) { //6.回滚事务platformTransactionManager.rollback platformTransactionManager.rollback(transactionStatus); } System.out.println(after: jdbcTemplate.queryForList(SELECT * from t_user)); }
4.2 代码分析 步骤一定义事务管理器PlatformTransactionManager 事务管理器相当于一个管理员这个管理员就是用来帮你控制事务的比如开启事务提交事务回滚事务等等。
spring中使用PlatformTransactionManager这个接口来表示事务管理器
public interface PlatformTransactionManager { //获取一个事务开启事务 TransactionStatus getTransaction(Nullable TransactionDefinition definition) throws TransactionException; //提交事务 void commit(TransactionStatus status) throws TransactionException; //回滚事务 void rollback(TransactionStatus status) throws TransactionException;}
步骤二定义事务属性TransactionDefinition 定义事务属性比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
spring中使用TransactionDefinition接口来表示事务的定义信息有个子类比较常用DefaultTransactionDefinition。
调用事务管理器的getTransaction方法即可以开启一个事务。这个方法会返回一个TransactionStatus表示事务状态的一个对象通过TransactionStatus提供的一些方法可以用来控制事务的一些状态比如事务最终是需要回滚还是需要提交。
步骤四执行业务操作事务管理器开启事务的时候会创建一个连接将datasource和connection映射之后丢在了ThreadLocal中而JdbcTemplate内部执行db操作的时候也需要获取连接JdbcTemplate会以自己内部的datasource去上面的threadlocal中找有没有关联的连接如果有直接拿来用若没找到将重新创建一个连接而此时是可以找到的那么JdbcTemplate就参与到spring的事务中了。
4.2 TransactionTemplateTest public void test2() throws Exception { //定义一个数据源 DataSource dataSource new DataSource(); dataSource.setDriverClassName(com.mysql.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/int?characterEncodingUTF-8&serverTimezoneUTC); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); //定义一个JdbcTemplate用来方便执行数据库增删改查 JdbcTemplate jdbcTemplate new JdbcTemplate(dataSource); //1.定义事务管理器给其指定一个数据源可以把事务管理器想象为一个人这个人来负责事务的控制操作 PlatformTransactionManager platformTransactionManager new DataSourceTransactionManager(dataSource); //2.定义事务属性TransactionDefinitionTransactionDefinition可以用来配置事务的属性信息比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。 DefaultTransactionDefinition transactionDefinition new DefaultTransactionDefinition(); transactionDefinition.setTimeout(10); //3.创建TransactionTemplate对象 TransactionTemplate transactionTemplate new TransactionTemplate(platformTransactionManager,transactionDefinition);/** * 4.通过TransactionTemplate提供的方法执行业务操作 * 主要有2个方法 * 1.executeWithoutResult(Consumer<TransactionStatus> action)没有返回值的需传递一个Consumer对象在accept方法中做业务操作 * 2.<T> T execute(TransactionCallback<T> action)有返回值的需要传递一个TransactionCallback对象在doInTransaction方法中做业务操作 * 调用execute方法或者executeWithoutResult方法执行完毕之后事务管理器会自动提交事务或者回滚事务。 * 那么什么时候事务会回滚有2种方式 * 1transactionStatus.setRollbackOnly();将事务状态标注为回滚状态 * 2execute方法或者executeWithoutResult方法内部抛出异常 * 什么时候事务会提交 * 方法没有异常 && 未调用过transactionStatus.setRollbackOnly(); */ transactionTemplate.executeWithoutResult(new Consumer<TransactionStatus>() { Override public void accept(TransactionStatus transactionStatus) { jdbcTemplate.update(insert into t_user (name) values (?), transactionTemplate-1); jdbcTemplate.update(insert into t_user (name) values (?), transactionTemplate-2); } }); System.out.println(after: jdbcTemplate.queryForList(SELECT * from t_user)); }