maven 项目搭建
添加事务注解
- 配置事务管理器(数据库相关的配置)
@EnableTransactionManagement // 开启事务注解支持
....
/**
* 装配事务管理实现对象
* @param dataSource
* @return
*/
@Bean
public TransactionManager transactionManager(DataSource dataSource){
// 内部要进行事务的操作,要基于连接池
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
- 使用声明事务注解
@Transactional
// 类中所有的方法都开启事务
@Transactional
@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
// 因为有修改操作,所以不启动只读模式
@Transactional(readOnly = false)
public void changeInfo(){
studentDao.updateAgeById(101,2);
System.out.println("-----------");
studentDao.updateNameById("test2",2);
}
// 只是查询,开启 只读模式 模式,加快数据查询速度
@Transactional(readOnly = true)
public void getStudentInfo(){
}
}
超时时间
- 事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。概括来说就是一句话:超时回滚,释放资源。
- 默认值是 -1 ,表示永远不超时。
// 因为有修改操作,所以不启动只读模式
@Transactional(readOnly = false, timeout = 3)
public void changeInfo(){
studentDao.updateAgeById(101,2);
System.out.println("-----------");
studentDao.updateNameById("test2",2);
}
事务异常
- 默认只针对运行时异常回滚,编译时异常不回滚。
@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
/**
* timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
*/
@Transactional(readOnly = false,timeout = 3)
public void changeInfo() throws FileNotFoundException {
studentDao.updateAgeById(100,1);
//主动抛出一个 IO异常 , 发现不会回滚,因为不在rollbackFor的默认范围内!
new FileInputStream("xxxx");
studentDao.updateNameById("test1",1);
}
}
- 设置回滚异常(rollbackFor属性:指定哪些异常类才会回滚,默认是 RuntimeException and Error 异常方可回滚!)
/**
* timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
*/
@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class)
public void changeInfo() throws FileNotFoundException {
studentDao.updateAgeById(100,1);
//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!
new FileInputStream("xxxx");
studentDao.updateNameById("test1",1);
}
- 设置不回滚的异常
noRollbackFor 属性:在rollbackFor的范围内,指定哪些异常不会回滚
@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
/**
* timeout设置事务超时时间,单位秒! 默认: -1 永不超时,不限制事务时间!
* rollbackFor = 指定哪些异常才会回滚,默认是 RuntimeException and Error 异常方可回滚!
* noRollbackFor = 指定哪些异常不会回滚, 默认没有指定,如果指定,应该在rollbackFor的范围内!
*/
@Transactional(readOnly = false,timeout = 3,rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class)
public void changeInfo() throws FileNotFoundException {
studentDao.updateAgeById(100,1);
//主动抛出一个检查异常,测试! 发现不会回滚,因为不在rollbackFor的默认范围内!
new FileInputStream("xxxx");
studentDao.updateNameById("test1",1);
}
}
事务隔离级别
@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
/**
* isolation = 设置事务的隔离级别,mysql默认是repeatable read!
*/
@Transactional(readOnly = false,isolation = Isolation.REPEATABLE_READ)
public void changeInfo() throws FileNotFoundException {
studentDao.updateAgeById(100,1);
studentDao.updateNameById("test1",1);
}
}
事务传播行为
- 声明两个业务方法
@Service
public class StudentService {
@Autowired
private StudentDao studentDao;
/**
* 声明两个独立修改数据库的事务业务方法
*/
@Transactional(propagation = Propagation.REQUIRED)
public void changeAge(){
studentDao.updateAgeById(99,1);
}
@Transactional(propagation = Propagation.REQUIRED)
public void changeName(){
studentDao.updateNameById("test2",1);
int i = 1/0;
}
}
- 声明一个整合业务方法
@Service
public class TopService {
@Autowired
private StudentService studentService;
@Transactional
public void topService(){
studentService.changeAge();
studentService.changeName();
}
}
因为设置了 propagation = Propagation.REQUIRED,所以 topService、changeAge、changeName 都在同一个事务中了,现在执行 changeAge 正常,但是 changeName 异常了,所以事务回滚,changeAge 修改的值也回滚了。
- propagation 属性的可选值
| 名称 | 含义 |
|---|---|
| REQUIRED 默认值 | 如果父方法有事务,就加入,如果没有就新建自己独立! |
| REQUIRES_NEW | 不管父方法是否有事务,我都新建事务,都是独立的! |
tips: 在同一个类中,对于@Transactional注解的方法调用,事务传播行为不会生效。这是因为Spring框架中使用代理模式实现了事务机制,在同一个类中的方法调用并不经过代理,而是通过对象的方法调用,因此@Transactional注解的设置不会被代理捕获,也就不会产生任何事务传播行为的效果。