SpringBoot使用事務(SpringBoot學習五)

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配置事務。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章