概述
Spring使用@Transactional 注解提供事务管理的快捷手段
常用参数
readOnly
@Transactional(readOnly = true)
@Transactional(readOnly = true)readOnly属性用来设置当前事务是否为只读事务(默认 false)
当事务被设置成只读事务时,增删改操作会导致报错
org.springframework.dao.TransientDataAccessResourceException:
### Error updating database. Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowedrollbackFor
@Transactional(rollbackFor = Exception.class)设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚
@Transactional默认只会回滚RuntimeException,如果发生非运行时异常不会回滚
propagation
用来设置事务的传播行为
常用的基本就这两个
@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况)
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务下面通过四个案例说明这两个事务的区别
case1:
@Transactional
public void Example1(User user) {
userDao.createUser(user);
propagationService.required();
}@Transactional
public void required() {
throw new NullPointerException("抛出异常1");
}@Test
public void Example1()
{
User user = new User();
user.setUsername("vito1");
transactionService.Example1(user);
}会回滚
case2:
@Transactional
public void Example2(User user) {
userDao.createUser(user);
try {
propagationService.required();
} catch (Exception e) {
e.printStackTrace();
}
}@Transactional
public void required() {
throw new NullPointerException("抛出异常1");
}@Test
public void Example2()
{
User user = new User();
user.setUsername("vito2");
transactionService.Example1(user);
}也会回滚,而且还会多报个错
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only case3:
@Transactional
public void Example3(User user) {
userDao.createUser(user);
propagationService.requiresNew();
}@Transactional(propagation=Propagation.REQUIRES_NEW)
public void requiredNew() {
throw new NullPointerException("抛出异常2");
}@Test
public void Example3()
{
User user = new User();
user.setUsername("vito3");
transactionService.Example3(user);
}也会回滚,但不会报case2的错
case4:
@Transactional
public void Example4(User user) {
userDao.createUser(user);
try {
propagationService.requiresNew();
} catch (Exception e) {
e.printStackTrace();
}
}@Transactional(propagation=Propagation.REQUIRES_NEW)
public void requiredNew() {
throw new NullPointerException("抛出异常2");
}@Test
public void Example4()
{
User user = new User();
user.setUsername("vito4");
transactionService.Example4(user);
}测试通过,并且数据成功插入
isolation
事务隔离级别,一般选择默认,即和数据库事务隔离级别一样
ISOLATION_DEFAULT 默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与 JDBC 的隔离级别相对应
ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。 这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生 (不可重复读)。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 除了防止脏读,不可重复读外,还避免了幻像读。
本文相关代码:github.com/kjlist/Bazo…
Tips
一个没有加 @Transactional 注解的方法,去调用一个加了 @Transactional 的方法,不会产生事务
reason:@Transactional底层使用的是AOP技术,利用了动态代理技术。
@Transactional 注解只能应用到 public 方法上