事务
首先,我们要知道事务是什么
构成单一逻辑工作单元的操作集合称为事务
事务的ACID特性
- 原子性:不可分割的最小操作单位,要么同时成功,要么同时失败
- 一致性:事务操作前后,数据总量不变
- 隔离性:多个事务之间相互独立
- 持久性:当事务提交或回滚后,数据会持久化的保存数据
传统编程的事务管理
在传统的JAVA数据库编程中,我们遵循的是打开连接-执行操作-提交事务-关闭连接,如下面的代码:
Connection con = getCon();con.setAutoCommit(false);con.prepareStatement("UPDATE...").execute();con.prepareStatement("UPDATE...").execute();con.commit();//conn.rollback();con.close();
这样就产生了很多模板代码,而且依靠程序员手动提交事务,也十分不可靠
Spring对事务的管理
Spring的事务管理分为两类
- 声明式事务
- 编程式事务
Spring定义了一个接口PlatformTransactionManager ,我们只需要使用其实现类,将数据源交其管理,即可实现Spring事务管理
@Configuration@EnableTransactionManagement // 开启事务管理@ComponentScan("wang.ismy.spring")public class Config { @Bean public DataSource dataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setUrl("jdbc:mysql:///test"); druidDataSource.setUsername("root"); druidDataSource.setPassword("123"); return druidDataSource; } @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource){ return new JdbcTemplate(dataSource); } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ return new DataSourceTransactionManager(dataSource); }}
这样,当你在你的service中抛出异常的时候,Spring就会自动帮你进行事务回滚
@Transactional(rollbackFor = Exception.class) // Spring默认只对运行期异常回滚,加上该属性,则设置回滚的异常类型为Exception public void transfer() { jdbcTemplate.execute("UPDATE account SET amount = 90 WHERE name = 'alice'"); int a=1/0; jdbcTemplate.execute("UPDATE account SET amount = 110 WHERE name = 'bob'"); }
属性
@Transactional注解的一些属性说明如下
- read-only:是否是只读事务。默认false,不只读。
- isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
- propagation:指定事务的传播行为。
- timeout:指定超时时间。默认值为:-1。永不超时。
- rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
- no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
理解事务的传播行为
- PROPAGATION_REQUIRED
![a566c6c4de0acb7bcc0c87338e4502f0.png](https://i-blog.csdnimg.cn/blog_migrate/d782b619678c99b1a68e30a18874e9c6.jpeg)
简单来说就是两个被事务管理的方法都将在同一个事务内执行
- PROPAGATION_REQUIRES_NEW
![43d55b113706c6f398397078baf5d6ed.png](https://i-blog.csdnimg.cn/blog_migrate/1a7defb4e4249f87d0add189d137a65e.jpeg)
而这个传播行为则是开启一个新事务
- PROPAGATION_NESTED
该传播行为则是与JDBC的保存点一样,它使用了物理事务的保存点的概念
编程式事务
一般来说,编程式事务很少用,它就是把一些对数据库的更新操作放在一起,来达到事务管理的目的
首先,我们需要一个
@Bean public TransactionTemplate transactionTemplate(PlatformTransactionManager manager){ return new TransactionTemplate(manager); }
在使用的时候注入这个Template进行操作
public void transfer(){ transactionTemplate.execute((TransactionCallback) status -> { String sql = "UPDATE account SET money = money -200 WHERE uid = 41"; String sql1 = "UPDATE account SET money = money +200 WHERE uid = 45"; jdbcTemplate.update(sql); jdbcTemplate.update(sql1); return null; }); }
这样,也能进行事务管理
原理
最后,来探讨一下Spring事务管理的原理
一句话,事务管理是通过AOP实现的,这个我们通过获取Bean的实际类型就知道
System.out.println(context.getBean(AccountService.class).getClass());// 结果:class wang.ismy.spring.AccountService$$EnhancerBySpringCGLIB$$f8bd6705
这是Spring官网给出的一个受事务管理的概念视图:
![f633f94d744f35cff33a372f7b05c773.png](https://i-blog.csdnimg.cn/blog_migrate/3a02a0cb428ef197c5be1301cd00e6ea.jpeg)
AOP增强了我们的Service类,当真实的方法被调用前与调用后,Spring替我们完成commit/rollback等操作,以实现事务管理