这一节在之前的代码中验证一下事务是否可以回滚
抛出Exception
修改之前UserServiceImpl类的addUser方法如下,在该方法中抛出一个Exception:
@Override
public void addUser(User user) throws Exception {
userDao.addUser(user);
throw new Exception();
}
此时事务是不会回滚的,因为默认情况下只有发生运行时异常之后spring才会进行事务的回滚,而这里抛出的Exception显然不是运行时异常。此时可以在方法上加入如下注解来设置当发生Exception之后会进行回滚:
@Transactional(rollbackFor = {Exception.class})
抛出RuntimeException
修改之前UserServiceImpl类的addUser方法如下,在该方法中抛出一个RuntimeException:
@Override
public void addUser(User user) throws Exception {
userDao.addUser(user);
throw new RuntimeException();
}
因为抛出了运行时异常,所以此时spring会进行事务回滚操作。
需要注意的是倘若在方法中捕获异常的话,那么会导致事务不会回滚:
@Override
public void addUser(User user) {
userDao.addUser(user);
try {
throw new RuntimeException();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
这时可以在catch中再次将异常抛出,此时事务会发生回滚:
@Override
public void addUser(User user) {
userDao.addUser(user);
try {
throw new RuntimeException();
} catch (RuntimeException e) {
e.printStackTrace();
//再次抛出异常
throw new RuntimeException();
}
}
下面这种写法会发生运行时异常,所以事务会进行回滚操作
@Override
public void addUser(User user) {
userDao.addUser(user);
int a = 1/0;
}
在使用spring默认的事务配置时,只有在抛出RuntimeException之后事务才会回滚,不要在Service层捕获异常(try…catch),如果一定要捕获的话,在catch中再次抛出异常即可。
验证事务的传播行为
之前简单介绍了一下事务的传播行为,现在通过代码来验证一下。如果要验证事务传播行为的话,这里需要新建一个Service,这里来新增一个需求,在添加用户的时候向日志表中添加一条数据。
新建一个日志表t_log,里面添加一个字段username
CREATE TABLE `t_log` (
`username` varchar(255)
)
创建mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.monkey1024.dao.LogDao">
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<insert id="addLog">
INSERT INTO t_log(username) VALUES (#{username})
</insert>
</mapper>
创建dao
public interface LogDao {
void addLog(String username);
}
创建service
@Service
public class LogServiceImpl implements LogService {
@Autowired
private LogDao logDao;
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addLog(String username) throws Exception {
logDao.addLog(username);
}
}
在userService中将LogService注入,并调用addLog方法
//注入service
@Autowired
private LogService logService;
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addUser(User user) throws Exception {
userDao.addUser(user);
logService.addLog(user.getName());
throw new NullPointerException();
}
在addUser方法中调用了addLog方法,并且抛出了一个空指针异常,倘若传播行为设置为Propagation.REQUIRED的话,这两个方法都会进行回滚。
倘若在addLog方法中将传播行为设置为Propagation.REQUIRES_NEW的话,addLog会开启新的事务,因此提交成功,addUser会回滚。