1. 程式人生 > >SpringCloud SpringBoot mybatis 分散式微服務(十八)Spring Boot中的事務管理

SpringCloud SpringBoot mybatis 分散式微服務(十八)Spring Boot中的事務管理

快速入門

在Spring Boot中,當我們使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依賴的時候,框架會自動預設分別注入DataSourceTransactionManager或JpaTransactionManager。所以我們不需要任何額外配置就可以用@Transactional註解進行事務的使用。

我們以之前實現的《用spring-data-jpa訪問資料庫》的示例Chapter3-2-2作為基礎工程進行事務的使用常識。

在該樣例工程中(若對該資料訪問方式不瞭解,可先閱讀該文章),我們引入了spring-data-jpa,並建立了User實體以及對User的資料訪問物件UserRepository,在ApplicationTest類中實現了使用UserRepository進行資料讀寫的單元測試用例,如下:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {

	@Autowired
	private UserRepository userRepository;

	@Test
	public void test() throws Exception {

		// 建立10條記錄
		userRepository.save(new User("AAA", 10));
		userRepository.save(new User("BBB", 20));
		userRepository.save(new User("CCC", 30));
		userRepository.save(new User("DDD", 40));
		userRepository.save(new User("EEE", 50));
		userRepository.save(new User("FFF", 60));
		userRepository.save(new User("GGG", 70));
		userRepository.save(new User("HHH", 80));
		userRepository.save(new User("III", 90));
		userRepository.save(new User("JJJ", 100));

		// 省略後續的一些驗證操作
	}


}

可以看到,在這個單元測試用例中,使用UserRepository物件連續建立了10個User實體到資料庫中,下面我們人為的來製造一些異常,看看會發生什麼情況。

通過定義User的name屬性長度為5,這樣通過建立時User實體的name屬性超長就可以觸發異常產生。

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false, length = 5)
    private String name;

    @Column(nullable = false)
    private Integer age;

    // 省略建構函式、getter和setter

}

修改測試用例中建立記錄的語句,將一條記錄的name長度超過5,如下:name為HHHHHHHHH的User物件將會丟擲異常。
// 建立10條記錄
userRepository.save(new User("AAA", 10));
userRepository.save(new User("BBB", 20));
userRepository.save(new User("CCC", 30));
userRepository.save(new User("DDD", 40));
userRepository.save(new User("EEE", 50));
userRepository.save(new User("FFF", 60));
userRepository.save(new User("GGG", 70));
userRepository.save(new User("HHHHHHHHHH", 80));
userRepository.save(new User("III", 90));
userRepository.save(new User("JJJ", 100));

執行測試用例,可以看到控制檯中丟擲瞭如下異常,name欄位超長:
2016-05-27 10:30:35.948  WARN 2660 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1406, SQLState: 22001
2016-05-27 10:30:35.948 ERROR 2660 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Data truncation: Data too long for column 'name' at row 1
2016-05-27 10:30:35.951  WARN 2660 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Warning Code: 1406, SQLState: HY000
2016-05-27 10:30:35.951  WARN 2660 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Data too long for column 'name' at row 1

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement

此時查資料庫中,建立了name從AAA到GGG的記錄,沒有HHHHHHHHHH、III、JJJ的記錄。而若這是一個希望保證完整性操作的情況下,AAA到GGG的記錄希望能在發生異常的時候被回退,這時候就可以使用事務讓它實現回退,做法非常簡單,我們只需要在test函式上新增註解即可。
@Test
@Transactional
public void test() throws Exception {

    // 省略測試內容

}

再來執行該測試用例,可以看到控制檯中輸出了回滾日誌(Rolled back transaction for test context),
2016-05-27 10:35:32.210  WARN 5672 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1406, SQLState: 22001
2016-05-27 10:35:32.210 ERROR 5672 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Data truncation: Data too long for column 'name' at row 1
2016-05-27 10:35:32.213  WARN 5672 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Warning Code: 1406, SQLState: HY000
2016-05-27 10:35:32.213  WARN 5672 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Data too long for column 'name' at row 1
2016-05-27 10:35:32.221  INFO 5672 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [[email protected] testClass = ApplicationTests, testInstance = [email protected], testMethod = [email protected], testException = org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not execute statement, mergedContextConfiguration = [[email protected] testClass = ApplicationTests, locations = '{}', classes = '{class com.didispace.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]].

再看資料庫中,User表就沒有AAA到GGG的使用者資料了,成功實現了自動回滾。

這裡主要通過單元測試演示瞭如何使用註解來宣告一個函式需要被事務管理,通常我們單元測試為了保證每個測試之間的資料獨立,會使用註解讓每個單元測試都能在結束時回滾。而真正在開發業務邏輯時,我們通常在service層介面中使用來對各個業務邏輯進行事務管理的配置,例如:

public interface UserService {
    
    @Transactional
    User login(String name, String password);
    
}

事務詳解

上面的例子中我們使用了預設的事務配置,可以滿足一些基本的事務需求,但是當我們專案較大較複雜時(比如,有多個數據源等),這時候需要在宣告事務時,指定不同的事務管理器。對於不同資料來源的事務管理配置可以見《Spring Boot多資料來源配置與使用》中的設定。在宣告事務時,只需要通過value屬性指定配置的事務管理器名即可,例如:@Transactional(value="transactionManagerPrimary")

除了指定不同的事務管理器之後,還能對事務進行隔離級別和傳播行為的控制,下面分別詳細解釋:

#### 隔離級別

隔離級別是指若干個併發的事務之間的隔離程度,與我們開發時候主要相關的場景包括:髒讀取、重複讀、幻讀。

我們可以看org.springframework.transaction.annotation.Isolation列舉類中定義了五個表示隔離級別的值:

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);
}

  • DEFAULT:這是預設值,表示使用底層資料庫的預設隔離級別。對大部分資料庫而言,通常這值就是:READ_COMMITTED
  • READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的資料。該級別不能防止髒讀和不可重複讀,因此很少使用該隔離級別。
  • READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的資料。該級別可以防止髒讀,這也是大多數情況下的推薦值。
  • REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。即使在多次查詢之間有新增的資料滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止髒讀和不可重複讀。
  • SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。

指定方法:通過使用isolation屬性設定,例如:

@Transactional(isolation = Isolation.DEFAULT)

傳播行為

所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。

我們可以看org.springframework.transaction.annotation.Propagation列舉類中定義了6個表示傳播行為的列舉值:

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
}

  • REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。
  • SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
  • MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。
  • REQUIRES_NEW:建立一個新的事務,如果當前存在事務,則把當前事務掛起。
  • NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
  • NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常。
  • NESTED:如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於REQUIRED

指定方法:通過使用propagation屬性設定,例如:

@Transactional(propagation = Propagation.REQUIRED)

原始碼來源

相關推薦

SpringCloud SpringBoot mybatis 分散式微服務Spring Boot事務管理

快速入門在Spring Boot中,當我們使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依賴的時候,框架會自動預設分別注入DataSourceTransactionManager或JpaTransactionM

SpringCloud SpringBoot mybatis 分散式微服務Spring Boot整合MyBatis

Spring中整合MyBatis就不多說了,最近大量使用Spring Boot,因此整理一下Spring Boot中整合MyBatis的步驟。搜了一下Spring Boot整合MyBatis的文章,方法都比較老,比較繁瑣。查了一下文件,實際已經支援較為簡單的整合與使用。下面就

SpringCloud SpringBoot mybatis 分散式微服務整合Redis

引入依賴:在pom檔案中新增redis依賴:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>

SpringCloud SpringBoot mybatis 分散式微服務Spring Boot 自定義配置檔案

上面介紹的是我們都把配置檔案寫到application.yml中。有時我們不願意把配置都寫到application配置檔案中,這時需要我們自定義配置檔案,比如test.properties:com.forezp.name=forezp com.forezp.age=12怎麼將

SpringCloud SpringBoot mybatis 分散式微服務Spring Boot使用Spring-data-jpa讓資料訪問更簡單

然而,在實際開發過程中,對資料庫的操作無非就“增刪改查”。就最為普遍的單表操作而言,除了表和欄位不同外,語句都是類似的,開發人員需要寫大量類似而枯燥的語句來完成業務邏輯。為了解決這些大量枯燥的資料操作語句,我們第一個想到的是使用ORM框架,比如:Hibernate。通過整合H

企業分散式微服務SpringCloud SpringBoot mybatis Spring Boot使用LDAP來統一管理使用者資訊

LDAP簡介LDAP(輕量級目錄訪問協議,Lightweight Directory Access Protocol)是實現提供被稱為目錄服務的資訊服務。目錄服務是一種特殊的資料庫系統,其專門針對讀取,瀏覽和搜尋操作進行了特定的優化。目錄一般用來包含描述性的,基於屬性的資訊並

企業分布式微服務SpringCloud SpringBoot mybatis Spring Boot使用LDAP來統一管理用戶信息

數據庫表 repo on() intellij attr ads get 可選 mail LDAP簡介 LDAP(輕量級目錄訪問協議,Lightweight Directory Access Protocol)是實現提供被稱為目錄服務的信息服務。目錄服務是一種特殊的數據庫系

spring-boot-routespring-boot-admin監控服務

`SpringBootAdmin`不是Spring官方提供的模組,它包含了`Client`和`Server`兩部分。server部分提供了使用者管理介面,client即為被監控的服務。client需要註冊到server端。 SpringBootAdmin提供了很少的幾個監控服務端點,需要依賴SpringBo

Spring BootSpring Boot使用單元測試

前言這次來介紹下Spring Boot中對單元測試的整合使用,本篇會通過以下4點來介紹,基本滿足日常需求Service層單元測試Controller層單元測試新斷言assertThat使用單元測試的回滾正文Spring Boot中引入單元測試很簡單,依賴如下:1 2 3 4

Spring Boot入門系列Spring Boot 開發環境熱部署

在實際的專案開發過中,當我們修改了某個java類檔案時,需要手動重新編譯、然後重新啟動程式的,整個過程比較麻煩,特別是專案啟動慢的時候,更是影響開發效率。其實Spring Boot的專案碰到這種情況,同樣也同樣需要經歷重新編譯、重新啟動程式的過程。 只不過 Spring Boot 提供了一個spring-bo

企業分布式微服務SpringCloud SpringBoot mybatis springboot在啟動時註入了哪些bean

contex 測試 gree names system com clas temp ice 在程序入口加入: @SpringBootApplication public class SpringbootFirstApplication { public stat

企業分布式微服務SpringCloud SpringBoot mybatis spring boot做調度任務

tro 一次 tis com href 什麽 init boot 2.6 構建工程 創建一個Springboot工程,在它的程序入口加上@EnableScheduling,開啟調度任務。 @SpringBootApplication @EnableScheduling p

企業分布式微服務SpringCloud SpringBoot mybatis Spring Boot使用JdbcTemplate訪問數據庫

ger sele 應該 創建 測試環境 oid reg tis eat 本文介紹在Spring Boot基礎下配置數據源和通過JdbcTemplate編寫數據訪問的示例。 數據源配置 在我們訪問數據庫的時候,需要先配置一個數據源,下面分別介紹一下幾種不同的數據庫配置方式。

企業分布式微服務SpringCloud SpringBoot mybatis Spring Boot使用Spring Security進行安全控制

spring ron public 控制 應用 app ebs cloud 來源 準備工作 首先,構建一個簡單的Web工程,以用於後續添加安全控制,也可以用之前Chapter3-1-2做為基礎工程。若對如何使用Spring Boot構建Web應用,可以先閱讀《Spring

企業分布式微服務SpringCloud SpringBoot mybatis Spring BootWeb應用的統一異常處理

src one exception learn 微服務 public .net 可能 訪問 我們在做Web應用的時候,請求處理過程中發生錯誤是非常常見的情況。Spring Boot提供了一個默認的映射:/error,當處理中拋出異常之後,會轉到該請求中處理,並且該請求有一個

springcloud Spring Boot mybatis分散式微服務雲架構(六):配置中心

下面針對該Controller編寫測試用例驗證正確性,具體如下。當然也可以通過瀏覽器外掛等進行請求提交驗證。 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes =

Spring Cloud Spring Boot mybatis分散式微服務雲架構快速入門

快速入門本章主要目標完成Spring Boot基礎專案的構建,並且實現一個簡單的Http請求處理,通過這個例子對Spring Boot有一個初步的瞭解,並體驗其結構簡單、開發快速的特性。系統要求:Java 7及以上Spring Framework 4.1.5及以上本文采用Ja

企業分布式SpringCloud+SpringBoot+Mybatis+shiro+微服務 技術分享

spring cloud spring boot springmvc mybatis eureka 介紹 Commonservice-system是一個大型分布式、微服務、面向企業的JavaEE體系快速研發平臺,基於模塊化、服務化、原子化、熱插拔的設計思想,使用成熟領先的無商業限制的主流

spring cloud網際網路分散式微服務雲平臺規劃分析--spring cloud平臺整體規

導語 近期公司孵化了一個網際網路產品,隨著業務發展,產品運營後用戶資料量(過億)、業務資料量(過100億)較大,技術團隊配合產品、運營快速定製化開發, 還要考慮產品涉及的資金安全、訊息的及時性、業務的制動化處理,我們選擇鴻鵠cloud分散式雲架構平臺作為公司產品核心企業架構。 產品平臺規

spring cloud網際網路分散式微服務雲平臺規劃分析--spring cloud平臺整體規劃

1. 導語 近期公司孵化了一個網際網路產品,隨著業務發展,產品運營後用戶資料量(過億)、業務資料量(過100億)較大,技術團隊配合產品、運營快速定製化開發, 還要考慮產品涉及的資金安全、訊息的及時性、業務的制動化處理,我們選擇鴻鵠cloud分散式雲架構平臺作為公司產品核心