什么时候用? |
在某个接口内需要进行事务处理的。比如在一个方法中,先要修改a表,然后将修改记录存到b表。业务需要这一系列操作是原子性的。
什么时候不用? |
加上事务会拖慢接口的响应速度,所以要慎重。
(1)接口是幂等的时候。比如我要从a表查询出数据,然后将数据新增或更新到b表。这本来就是幂等的,不用加事务。
(2)本来就是事务的情况,比如批量插入个list。【这块需要注意,数据库的批量插入本来就是原子性的,等insert方法执行完后,这批数据才会一下子出现在库里。执行期间,库里是不会动态新增数据的】
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO your_table (column1, column2, ...)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
(#{item.field1}, #{item.field2}, ...)
</foreach>
</insert>
怎么用 |
1、在Spring配置文件或者启动类中添加注解
@Configuration
@EnableTransactionManagement
public class AppConfig {
}
2、在serviceImpl类里的对应方法上加上@Transactional注解
@Transactional(rollbackFor = Exception.class)
@Override
public void test(){
}
使用时的注意事项 |
1、和多线程一起使用
当在事务里面使用到了多线程,可以使用countDownLatch这些同步工具类处理。
当在多线程里面使用到了事务,那只能保证单个线程的操作是原子性的。
2、和try catch一起使用时,需要throws
@Transactional(rollbackFor = Exception.class)
public void transactionalTest()
{
try
{
User user = new User().setName("张三");
userService.insertUser(user);
int i = 1 / 0;
}
catch (Exception e)
{
log.error("执行事务异常,需要回滚", e);
//这块是必须的,否则异常被catch捕获了,那程序就不会回滚了
throw e;
}
}
3、默认状态下,非RuntimeException不会触发回滚
@Transactional注解只能在抛出RuntimeException或者Error时才会触发事务的回滚,常见的非RuntimeException是不会触发事务的回滚的。但是我们平时做业务处理时,需要捕获异常,所以可以手动抛出RuntimeException异常或者添加rollbackFor = Exception.class(也可以指定相应异常)
4、只能使用在public方法上
5、类内方法间的调用
(1)不管是主子方法上都有@Transactional,还是只有主方法上有@Transactional,当主方法或子方法内部出现异常时,都会回滚。
(2)但如果只有子方法上有@Transactional,即使子方法出现异常,也不会回滚。也就是事务失效了。栗子如下:
@Override
public Long addBook(Book book)
{
Long result = add(book);
int i = 1 / 0;
return result;
}
@Transactional
public Long add(Book book)
{
Long result = bookDao.addBook(book);
return result;
}