在实际开发中,对于一组数据库操作特别是增删改操作,为了保证原子性,通过需要用事务来控制,要么全部成功,要么全部失败。Spring中可以通过注解@Transaction
常用的方法如下:
- @Transactional
- public void testTransaction(User user) {
- int rowNum = userMapper.insertUser(user);
- List<User> userList = userMapper.selectAllUsers();
- }
这里将两个操作insert和select当作原子操作,如果在testTransaction方法中有异常,则回滚。(注意:这个事务是MySQL层控制,回滚的操作也是MySQL控制的)。
需要注意的问题:
(1)尽可能将MySQL执行语句往方法体后面靠:
- @Transactional
- public void testTransaction(User user) {
- int rowNum = userMapper.insertUser(user);
- doSomething(); // 这个doSomthing 可能耗时较长
- List<User> userList = userMapper.selectAllUsers();
- }
如果可以移动的话,可以将doSomething()可能耗时较长,移动到int rowNum=userMapper.insertUser(user)的前面,即:
- @Transactional
- public void testTransaction(User user) {
- doSomething(); // 这个doSomthing 可能耗时较长
- int rowNum = userMapper.insertUser(user);
- List<User> userList = userMapper.selectAllUsers();
- }
因为,MySQL事务的commit语句是在第一次执行MySQL相关语句开始,一直到方法的结束。
(2)设置事务的超时时间(如果不设置默认是-1是无限长)
- @Transactional(timeout = 5)
- public void testTransaction(User user) throws InterruptedException {
- Thread.sleep(2000);
- List<User> userList = userMapper.selectAllUsers(); // 耗时:1s
- int rowNum = userMapper.insertUser(user); // 耗时 1s
- Thread.sleep(3000);
- }
加入另外两个MySQL相关的操作耗时都是1s,则上述事务是不会报超时异常。
timeout的计算的事务超时 = 最后一个MySQL语句耗时 + 以及最后一个MySQL之前的所有耗时。因此,上述耗时为2s+1s+1s=4s,没有超过5s,因此不会报事务超时异常,这个需要特别注意,如果想了解具体原理,可以查看源码,或者看该文档:http://jinnianshilongnian.iteye.com/blog/1986023