首先,我们要知道事务是什么
构成单一逻辑工作单元的操作集合称为事务
在传统的JAVA数据库编程中,我们遵循的是打开连接-执行操作-提交事务-关闭连接,如下面的代码:
Connection con = getCon();
con.setAutoCommit(false);
con.prepareStatement("UPDATE...").execute();
con.prepareStatement("UPDATE...").execute();
con.commit();
//conn.rollback();
con.close();
这样就产生了很多模板代码,而且依靠程序员手动提交事务,也十分不可靠
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
注解的一些属性说明如下
简单来说就是两个被事务管理的方法都将在同一个事务内执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Js4iUWgF-1575086151289)(https://docs.spring.io/spring/docs/5.2.1.RELEASE/spring-framework-reference/images/tx_prop_requires_new.png)]
而这个传播行为则是开启一个新事务
该传播行为则是与JDBC的保存点一样,它使用了物理事务的保存点的概念
一般来说,编程式事务很少用,它就是把一些对数据库的更新操作放在一起,来达到事务管理的目的
首先,我们需要一个
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager manager){
return new TransactionTemplate(manager);
}
在使用的时候注入这个Template进行操作
public void transfer(){
transactionTemplate.execute((TransactionCallback<Void>) 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官网给出的一个受事务管理的概念视图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IcLIP2fR-1575086151289)(https://docs.spring.io/spring/docs/5.2.1.RELEASE/spring-framework-reference/images/tx.png)]
AOP增强了我们的Service类,当真实的方法被调用前与调用后,Spring替我们完成commit/rollback等操作,以实现事务管理