声明式事务
事务是描述对数据库的一组操作,比如在转账业务中,A向B转了一笔钱,那么从A的账户中扣款和把钱打入B的账户这两个数据操作就应该放在一个事务中,不允许只单独执行其中一个操作,如果在事务执行过程中有错误产生,则整个事务中的操作需要全部回退。关于事务可以了解一下事务的ACID特性
Spring对事务做了支持,可以用注解标记一个方法中的操作为一组事务,这就是Spring声明式事务
为了测试,我们创建一个Service类,定义一个新增操作的方法,这个方法一定会产生一个异常,来模拟业务产生错误的情景
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
PersonMapper personMapper;
@Override
public int insertPerson(Person person) {
personMapper.insert(person);
throw new RuntimeException();
}
}
这时候方法是没有开启事务功能的,注入Service类并调用新增方法
@SpringBootTest
class MyTest {
@Autowired
PersonService personService;
@Test
void test() {
Person person = new Person("cong", "HZ", 18);
personService.insertPerson(person);
}
}
执行之后方法抛出异常
查看数据库,可以发现由于没有开启事务,数据还是被插入到数据库中,并没有因为发生了错误就回退
基本使用
开启事务功能,首先在需要开启事务的方法上添加@Transactional
注解
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
PersonMapper personMapper;
@Transactional
@Override
public int insertPerson(Person person) {
personMapper.insert(person);
throw new RuntimeException();
}
}
然后在配置类或者主启动类上添加@EnableTransactionManagement
注解
@EnableTransactionManagement
@SpringBootApplication
public class SpringDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDemoApplication.class, args);
}
}
再次调用新增方法,新增第二条数据
@SpringBootTest
class MyTest {
@Autowired
PersonService personService;
@Test
void test() {
Person person = new Person("zhang", "BJ", 18);
personService.insertPerson(person);
}
}
方法抛出了异常,不过这次我们可以看到控制台的日志显示有事务启动
查看数据库,发现由于启动了事务,在方法中出现异常时,事务发生了回滚,所以第二条数据没有被插入
属性详解
在@Transactional
注解中,有很多属性可以配置,以下介绍一些常用的属性配置
propagation
propagation属性用于设置事务的传播行为,传播行为意思就是在两个都启用了事务的方法进行嵌套调用时,外层事务和内层事务的执行动作,Spring有以下七种事务传播行为:
- REQUIRED
- SUPPORTS
- MANDATORY
- REQUIRES_NEW
- NOT_SUPPORTED
- NEVER
- NESTED
关于具体的事务传播行为分析,可以看我的这篇文章:
isolation
isolation属性用于设置事务的隔离级别,不同的隔离级别对脏读,幻读,不可重读这三个事务问题的解决不同。Spring默认使用数据库的隔离级别(MySQL默认为REPEATABLE_READ),Spring一共支持以下五种隔离级别:
- 默认:DEFAULT
- 读未提交:READ_UNCOMMITTED
- 读已提交:READ_COMMITTED
- 可重复读:REPEATABLE_READ
- 串行化:SERIALIZABLE
timeout
通过设置timeout属性,可以指定方法在几秒内需要完成,如果超时则直接回滚,默认值为-1
readOnly
readOnly属性默认为false,如果设置为true,则方法中的操作只能对数据库进行查询操作,禁止增删改操作
rollbackFor/noRollbackFor
meout属性,可以指定方法在几秒内需要完成,如果超时则直接回滚,默认值为-1
readOnly
readOnly属性默认为false,如果设置为true,则方法中的操作只能对数据库进行查询操作,禁止增删改操作
rollbackFor/noRollbackFor
rollbackFor属性可以指定哪些异常需要回滚,noRollbackFor属性则可以指定哪些异常不需要回滚