SpringBoot使用事務
上次瞭解了MySQL的事務概念,下面就開始編寫代碼來實際理解一下概念。
配置上面沒有什麼新加的配置,使用的數據庫是MySQL,集成的Mybatis。按照之前的博客配置就可以了,這裏不再累述。下面就直接上代碼。然後說一下遇到的問題。
package com.psq.train.mysql;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* TransactionalTrain.java
* Description: SpringBoot數據庫事務練習
*
* @author Peng Shiquan
* @date 2020/6/13
*/
@Service
public class TransactionalTrain extends SqlSessionDaoSupport {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
@Resource
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
//@PostConstruct
public void mybatisTransactionalTrain() {
//開啓事務
SqlSession sqlSession = sqlSessionFactory.openSession(false);
TestUser testUser = new TestUser();
testUser.setId(3);
testUser.setName("qsp");
testUser.setPassword("87654321");
try {
Integer saveResult = sqlSession.insert("com.psq.train.dao.UserMapper.insertUser", testUser);
//重複插入,id相同一定回產生異常
Integer saveResult2 = sqlSession.insert("com.psq.train.dao.UserMapper.insertUser", testUser);
sqlSession.commit();
} catch (Exception e) {
System.err.println("事務開始回滾");
sqlSession.rollback();
System.err.println("事務回滾成功");
throw e;
} finally {
sqlSession.close();
}
}
}
首先是SqlSessionFactory
的注入,因爲Mybatis取消了SqlSessionFactory
的自動注入,所以這裏需要繼承一下SqlSessionDaoSupport
,再重寫一下setSqlSessionFactory
方法。後面其他方法就可以使用一下代碼正常注入了:
@Autowired
private SqlSessionFactory sqlSessionFactory;
下面就是邏輯代碼的堆疊了,需要注意的就是sqlSessionFactory.openSession(false);
的意思是關閉自動提交,這樣就可以測試事務了。然後就是插入兩個主鍵相同的列,第一個可以正常插入,第二個因爲逐漸相同會插入失敗,導致異常,捕獲異常後執行sqlSession.rollback();
就可以回滾了。這裏也有一個地方,執行sqlSession.close();
的時候也會執行回滾,通過看源碼的時候可以發現最後是執行了回滾操作的。
然後問題就來了,這裏我嘗試了很多次,事務回滾一直沒有執行成功,數據庫中最後仍然是一條數據。排查了很多的地方還是不行,這裏也希望大神能夠指導一下。
最後沒有辦法,只能通過Spring來實現事務。
Spring中的事務管理分爲編程式事務管理和聲明式事務管理。編程式事務管理現在使用的已經很少了,現在大部分都是聲明式事務管理。我這裏也是通過註解的形式來實現事務的管理。上代碼。
package com.psq.train.mysql;
import com.psq.train.dao.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* SpringTransactionalTrain.java
* Description: 使用Spring來管理事務
*
* @author Peng Shiquan
* @date 2020/6/13
*/
@Component
public class SpringTransactionalTrain {
@Autowired
private UserMapper userMapper;
@Transactional
public void mybatisTransactionalTrain() {
TestUser testUser = new TestUser();
testUser.setId(3);
testUser.setName("psq");
testUser.setPassword("9876");
System.err.println(testUser.toString());
try {
Integer saveResult = userMapper.insertUser(testUser);
System.err.println("插入成功");
//一定會報異常
Integer saveResult2 = userMapper.insertUser(testUser);
} catch (Exception e) {
System.err.println(e);
System.err.println("開始回滾");
throw e;
}
}
}
通過controller層的調用,controller層代碼如下:
package com.psq.train.controller;
import com.psq.train.dao.UserMapper;
import com.psq.train.mysql.SpringTransactionalTrain;
import com.psq.train.mysql.TestUser;
import com.psq.train.mysql.TransactionalTrain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* TransactionalController.java
* Description: controller類,用於測試
*
* @author Peng Shiquan
* @date 2020/6/13
*/
@RestController
public class TransactionalController {
@Autowired
private SpringTransactionalTrain springTransactionalTrain;
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String saveTestUser() {
springTransactionalTrain.mybatisTransactionalTrain();
return "hello";
}
}
按照上面的代碼,事務就可以正常回滾。數據庫中就沒有新插入的記錄。
下面就簡單說一下spring中的事務的一些信息。
- 事務的傳播行爲
- propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是Spring默認的選擇。
- propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行。
- propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出異常。
- propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起。
- propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
- propagation_never:以非事務方式執行操作,如果當前事務存在則拋出異常。
- propagation_nested:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與propagation_required類似的操作。
- 事務的實現方式
- 編程式事務管理對基於 POJO 的應用來說是唯一選擇。我們需要在代碼中調用beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。
- 基於 TransactionProxyFactoryBean的聲明式事務管理。
- 基於 @Transactional 的聲明式事務管理。
- 基於Aspectj AOP配置事務。