最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中的聲明式事務詳解

 更新時間:2023年08月10日 09:03:07   作者:ycfxhsw  
這篇文章主要介紹了SpringBoot中的聲明式事務詳解,Spring采用統(tǒng)一的機制來處理不同的數(shù)據(jù)訪問技術的事務, Spring的事務提供一個PlatformTransactionManager的接口,不同的數(shù)據(jù)訪問技術使用不同的接口實現(xiàn),需要的朋友可以參考下

事務

所有數(shù)據(jù)訪問技術都有事務機制,這些技術提供了API來開啟事務、提交事務完成數(shù)據(jù)操作,或者在發(fā)生錯誤的時候回滾數(shù)據(jù)。

Spring采用統(tǒng)一的機制來處理不同的數(shù)據(jù)訪問技術的事務, Spring的事務提供一個 PlatformTransactionManager 的接口,不同的數(shù)據(jù)訪問技術使用不同的接口實現(xiàn)。

Data Tech實現(xiàn)
JDBCDataSourceTransactionManager
JPAJPATransactionManager
HibernateHibernateTransactionManager
JDOJDOTransactionManager
分布式事務JtaTransactionManager

Mybatis-Spring依賴于 DataSourceTransactionManager ,沒有自己實現(xiàn) PlatformTransactionManager。

而得益于SpringBoot的自動配置機制,為我們自動開啟了聲明式事務支持, 我們無需添加注解 @EnableTransactionManagement

事務基礎

Spring提供一個 @EnableTransactionManagement 注解在配置類上開啟聲明式事務支持, 自動掃描加了 @Transactional 注解的類和方法,加入事務支持。

@Transactional 的配置項:

配置項含義備注
value定義事務管理器它是 SpringIOC 容器的一個Bean id,這個Bean需要實現(xiàn)接口 PlatformTransactionManager
transactionManager定義事務管理器它是 SpringIOC 容器的一個Bean id,這個Bean需要實現(xiàn)接口 PlatformTransactionManager
isolation隔離級別這是一個數(shù)據(jù)庫在多個事務同時存在時的概念。默認值是數(shù)據(jù)庫默認隔離級別
propagation傳播行為傳播行為是方法之間調用的問題。默認值為Progation.REQUIRED
timeout超時時間單位為秒,當超時時,會引發(fā)異常,默認會導致事務回滾
readOnly是否開啟只讀事務默認 false
rollbackFor回滾事務的異常類定義只有當方法產(chǎn)生所定義的異常時,才會回滾事務,否則提交事務
rollbackForClassName回滾事務的異常類名定義同 rollbackFor,只是使用類名稱定義
noRollbackFor當產(chǎn)生哪些異常不回滾事務當產(chǎn)生所定義異常時,Spring將繼續(xù)提交事務
noRollbackForClassName當產(chǎn)生哪些異常不回滾事務同 noRollbackFor,只是使用類名稱定義

propagation

事務的傳播機制,主要有以下幾種,默認是 REQUIRED:

  1. REQUIRED - 方法A調用時候沒有事務新建一個事務,在方法A中調用方法B,將使用相同的事務,如果方法B發(fā)生異常需要回滾,整個事務回滾。
  2. REQUIRES_NEW - 方法A調用方法B時,無論是否存在事務都開啟一個新事務,這樣B方法異常不會導致A的數(shù)據(jù)回滾。
  3. NESTED - 和REQUIRES_NEW類似,但是只支持JDBC,不支持JPA或Hibernate
  4. SUPPORTS - 方法調用時有事務就用事務,沒事務就不用事務
  5. NOT_SUPPORTED - 強制方法不在事務中執(zhí)行,若有事務,在方法調用到結束階段先掛起事務。
  6. NEVER - 強制不能有事務,若有事務就拋出異常
  7. MANDATORY - 強制必須有事務,如果沒有事務就拋出異常

isolation

事務的隔離級別,決定了事務的完整性,主要一下幾種,默認是DEFAULT:

  1. READ_UNCOMMITTED - A事務修改記錄但沒提交,B事務可讀取到修改后的值??蓪е屡K讀、不可重復讀、幻讀。
  2. READ_COMMITTED - A事務修改并提交后,B事務才能讀取到修改后的值,阻止了臟讀,但可能導致不可重復讀和幻讀。
  3. REPEATABLE_READ - A事務讀取了一條記錄,B事務將不能修改這條記錄,阻止臟讀和不可重復讀,但是可能出現(xiàn)幻讀。
  4. SERIALIZABLE - 事務是順序執(zhí)行的,可避免所有缺陷,但是開銷很大。
  5. DEFAULT - 使用當前數(shù)據(jù)庫默認隔離級別,入Oracle、SQL Server是READ_COMMITTED,MySQL是REPEATABLE_READ

timeout

事務過期時間,默認是當前數(shù)據(jù)庫默認事務過期時間。

readOnly

指定是否為只讀事務,默認是false。

如果你一次執(zhí)行單條查詢語句,則沒有必要啟用事務支持,數(shù)據(jù)庫默認支持SQL執(zhí)行期間的讀一致性。

如果你一次執(zhí)行多條查詢語句,例如統(tǒng)計查詢,報表查詢,在這種場景下,多條查詢SQL必須保證整體的讀一致性, 否則,在前條SQL查詢之后,后條SQL查詢之前,數(shù)據(jù)被其他用戶改變,則該次整體的統(tǒng)計查詢將會出現(xiàn)讀數(shù)據(jù)不一致的狀態(tài), 此時,應該啟用只讀事務支持。

只讀事務與讀寫事務區(qū)別:

對于只讀查詢,可以指定事務類型為 readonly,即只讀事務。

由于只讀事務不存在數(shù)據(jù)的修改, 因此數(shù)據(jù)庫將會為只讀事務提供一些優(yōu)化手段,例如Oracle對于只讀事務,不啟動回滾段,不記錄回滾log。

rollbackFor

指定哪些異常可以導致事務回滾,默認是 Throwable 的子類。

noRollbackFor

執(zhí)行哪些異常不可用引起事務回滾,默認是 Throwable 的子類。

實戰(zhàn)篇

實際項目中,使用SpringBoot的默認配置就已經(jīng)足夠滿足我們的需求了。 本篇將通過幾個例子來演示如何使用@Transactional注解,在出現(xiàn)異常時候回滾或不回滾數(shù)據(jù)。

使用的DAO技術是MyBatis進行數(shù)據(jù)訪問,使用druid數(shù)據(jù)庫連接池, 另外配合mybatis-plus,實現(xiàn)數(shù)據(jù)訪問層。

引入依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>${mysql-connector.version}</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>${druid.version}</version>
</dependency>
<!-- MyBatis plus增強和springboot的集成-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>${mybatis-plus.version}</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatisplus-spring-boot-starter</artifactId>
    <version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>

配置數(shù)據(jù)庫連接:

###################  spring配置  ###################
spring:
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8
    username: root
    password: xxxxx

然后增加mybatis個性化配置:

###################  mybatis-plus配置  ###################
mybatis-plus:
  mapper-locations: classpath*:com/xncoding/trans/dao/repository/mapping/*.xml
  typeAliasesPackage: >
    com.dao.entity
  global-config:
    id-type: 0  # 0:數(shù)據(jù)庫ID自增   1:用戶輸入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)
    db-column-underline: false
    refresh-mapper: true
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: true #配置的緩存的全局開關
    lazyLoadingEnabled: true #延時加載的開關
    multipleResultSetsEnabled: true #開啟的話,延時加載一個屬性時會加載該對象全部屬性,否則按需加載屬性

增加實體類User:

@TableName(value = "t_user")
public class User extends Model<User> {
    /**
     * 主鍵ID
     */
    @TableId(value="id", type= IdType.AUTO)
    private Integer id;
    private String username;
    private String password;
    // 省略 get/set 方法
    @Override
    protected Serializable pkVal() {
        return this.id;
    }
}

增加 UserMapper 類:

public interface UserMapper extends BaseMapper<User> {}

增加 Mybatis 配置類:

@Configuration
@EnableTransactionManagement(order = 2)
@MapperScan(basePackages = {"com.dao.repository"})
public class MybatisPlusConfig {
    @Resource
    private DruidProperties druidProperties;
    /**
     * 單數(shù)據(jù)源連接池配置
     */
    @Bean
    public DruidDataSource singleDatasource() {
        DruidDataSource dataSource = new DruidDataSource();
        druidProperties.config(dataSource);
        return dataSource;
    }
}

定義Service,并注入UserMapper:

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
}

增加Controller,注入Service,定義幾個url來做測試用:

@RestController
public class UserController {
    @Resource
    private UserService userService;
}

到此為止項目初始化完成,可以在Service中添加方法進行聲明式事務測試了。

異?;貪L

@Transactional 注解可以放到類也可以放到方法上,如果放到類上面會對所有 public 方法添加注解, 不過你仍然可以在方法上面加這個注解,會覆蓋類上面聲明的事務注解。

先實驗一個拋出異常會回滾的方法:

/**
 * 增刪改要寫 ReadOnly=false 為可寫
 * @param user 用戶
 */
@Transactional(readOnly = false)
public void updateUserError(User user) {
    userMapper.updateById(user);
    errMethod(); // 執(zhí)行一個會拋出異常的方法
}
private void errMethod() {
    System.out.println("error");
    throw new RuntimeException("runtime");
}

然后在Controller里面添加一個url調用此方法:

&#64;RequestMapping(&#34;/errorUpdate&#34;)    public Object first() {<!-- -->        User user &#61; new User();        user.setId(1);        user.setUsername(&#34;admin&#34;);        user.setPassword(&#34;admin&#34;);        userService.updateUserError(user);        return &#34;first controller&#34;;    }}

數(shù)據(jù)庫里面先插入一條數(shù)據(jù): 1|admin|123

啟動應用后訪問地址: //localhost:8092/errorUpdate

控制臺打印異常:

@RequestMapping("/errorUpdate")
    public Object first() {
        User user = new User();
        user.setId(1);
        user.setUsername("admin");
        user.setPassword("admin");
        userService.updateUserError(user);
        return "first controller";
    }
}

查看數(shù)據(jù)庫中記錄: 1|admin|123 ,沒有變動,說明回滾成功。

異常不回滾

你還可以指定特定異常不回滾,比如自定義一個MyException,拋出這個異常不回滾。

public class MyException extends RuntimeException {
    public MyException() {
        super();
    }
    public MyException(String runtime) {
        super(runtime);
    }
}

然后通過指定這個異常不回滾:

@Transactional(readOnly = false, noRollbackFor = {MyException.class})
public void updateUserError2(User user) {
    userMapper.updateById(user);
    errMethod2(); // 執(zhí)行一個會拋出自定義異常的方法
}
private void errMethod2() {
    System.out.println("error");
    throw new MyException("runtime");
}

然后再定義一個url來驗證:

@RequestMapping("/errorUpdate2")
public Object second() {
    User user = new User();
    user.setId(1);
    user.setUsername("admin");
    user.setPassword("admin");
    userService.updateUserError(user);
    return "second controller";
}

重啟服務器,訪問地址://localhost:8092/errorUpdate2

控制臺仍然報異常:

Caused by: com.xncoding.trans.exception.MyException: runtime
    at com.xncoding.trans.service.UserService.errMethod2(UserService.java:43) ~[classes/:na]
    at com.xncoding.trans.service.UserService.updateUserError2(UserService.java:34) ~[classes/:na]

看看數(shù)據(jù)庫中記錄:1|admin|admin,更改成功,說明拋出這個MyException異常后并不會回滾。

到此這篇關于SpringBoot中的聲明式事務詳解的文章就介紹到這了,更多相關SpringBoot聲明式事務內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

天峻县| 当雄县| 宽甸| 登封市| 和顺县| 沙洋县| 伊吾县| 常州市| 苏尼特左旗| 龙门县| 噶尔县| 宝兴县| 永靖县| 三都| 龙井市| 平乐县| 年辖:市辖区| 西昌市| 会理县| 荔波县| 深泽县| 崇文区| 宕昌县| 东光县| 余庆县| 通榆县| 喜德县| 永年县| 当阳市| 河东区| 高唐县| 大新县| 西丰县| 襄城县| 白玉县| 麦盖提县| 婺源县| 大关县| 环江| 缙云县| 罗田县|