欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring @Transactional注解的聲明式事務(wù)簡(jiǎn)化業(yè)務(wù)邏輯中的事務(wù)管理

 更新時(shí)間:2023年10月15日 10:51:45   作者:程序員大彬  
這篇文章主要為大家介紹了Spring @Transactional注解的聲明式事務(wù)簡(jiǎn)化業(yè)務(wù)邏輯中的事務(wù)管理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

面的幾個(gè)章節(jié)已經(jīng)分析了spring基于@AspectJ的源碼,那么接下來(lái)我們分析一下Aop的另一個(gè)重要功能,事物管理

事務(wù)的介紹

1.數(shù)據(jù)庫(kù)事物特性

  • 原子性
    多個(gè)數(shù)據(jù)庫(kù)操作是不可分割的,只有所有的操作都執(zhí)行成功,事物才能被提交;只要有一個(gè)操作執(zhí)行失敗,那么所有的操作都要回滾,數(shù)據(jù)庫(kù)狀態(tài)必須回復(fù)到操作之前的狀態(tài)
  • 一致性
    事物操作成功后,數(shù)據(jù)庫(kù)的狀態(tài)和業(yè)務(wù)規(guī)則必須一致。例如:從A賬戶轉(zhuǎn)賬100元到B賬戶,無(wú)論數(shù)據(jù)庫(kù)操作成功失敗,A和B兩個(gè)賬戶的存款總額是不變的。
  • 隔離性
    當(dāng)并發(fā)操作時(shí),不同的數(shù)據(jù)庫(kù)事物之間不會(huì)相互干擾(當(dāng)然這個(gè)事物隔離級(jí)別也是有關(guān)系的)
  • 持久性
    事物提交成功之后,事物中的所有數(shù)據(jù)都必須持久化到數(shù)據(jù)庫(kù)中。即使事物提交之后數(shù)據(jù)庫(kù)立刻崩潰,也需要保證數(shù)據(jù)能能夠被恢復(fù)。

2.事物隔離級(jí)別

當(dāng)數(shù)據(jù)庫(kù)并發(fā)操作時(shí),可能會(huì)引起臟讀、不可重復(fù)讀、幻讀、第一類(lèi)丟失更新、第二類(lèi)更新丟失等現(xiàn)象。

  • 臟讀
    事物A讀取事物B尚未提交的更改數(shù)據(jù),并做了修改;此時(shí)如果事物B回滾,那么事物A讀取到的數(shù)據(jù)是無(wú)效的,此時(shí)就發(fā)生了臟讀。
  • 不可重復(fù)讀
    一個(gè)事務(wù)執(zhí)行相同的查詢兩次或兩次以上,每次都得到不同的數(shù)據(jù)。如:A事物下查詢賬戶余額,此時(shí)恰巧B事物給賬戶里轉(zhuǎn)賬100元,A事物再次查詢賬戶余額,那么A事物的兩次查詢結(jié)果是不一致的。
  • 幻讀
    A事物讀取B事物提交的新增數(shù)據(jù),此時(shí)A事物將出現(xiàn)幻讀現(xiàn)象?;米x與不可重復(fù)讀容易混淆,如何區(qū)分呢?幻讀是讀取到了其他事物提交的新數(shù)據(jù),不可重復(fù)讀是讀取到了已經(jīng)提交事物的更改數(shù)據(jù)(修改或刪除)

對(duì)于以上問(wèn)題,可以有多個(gè)解決方案,設(shè)置數(shù)據(jù)庫(kù)事物隔離級(jí)別就是其中的一種,數(shù)據(jù)庫(kù)事物隔離級(jí)別分為四個(gè)等級(jí),通過(guò)一個(gè)表格描述其作用。

隔離級(jí)別臟讀不可重復(fù)讀幻象讀
READ UNCOMMITTED允許允許允許
READ COMMITTED臟讀允許允許
REPEATABLE READ不允許不允許允許
SERIALIZABLE不允許不允許不允許

3.Spring事物支持核心接口

  • TransactionDefinition-->定義與spring兼容的事務(wù)屬性的接口
public interface TransactionDefinition {
    // 如果當(dāng)前沒(méi)有事物,則新建一個(gè)事物;如果已經(jīng)存在一個(gè)事物,則加入到這個(gè)事物中。
    int PROPAGATION_REQUIRED = 0;
    // 支持當(dāng)前事物,如果當(dāng)前沒(méi)有事物,則以非事物方式執(zhí)行。
    int PROPAGATION_SUPPORTS = 1;
    // 使用當(dāng)前事物,如果當(dāng)前沒(méi)有事物,則拋出異常。
    int PROPAGATION_MANDATORY = 2;
    // 新建事物,如果當(dāng)前已經(jīng)存在事物,則掛起當(dāng)前事物。
    int PROPAGATION_REQUIRES_NEW = 3;
    // 以非事物方式執(zhí)行,如果當(dāng)前存在事物,則掛起當(dāng)前事物。
    int PROPAGATION_NOT_SUPPORTED = 4;
    // 以非事物方式執(zhí)行,如果當(dāng)前存在事物,則拋出異常。
    int PROPAGATION_NEVER = 5;
    // 如果當(dāng)前存在事物,則在嵌套事物內(nèi)執(zhí)行;如果當(dāng)前沒(méi)有事物,則與PROPAGATION_REQUIRED傳播特性相同
    int PROPAGATION_NESTED = 6;
    // 使用后端數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別。
    int ISOLATION_DEFAULT = -1;
    // READ_UNCOMMITTED 隔離級(jí)別
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    // READ_COMMITTED 隔離級(jí)別
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    // REPEATABLE_READ 隔離級(jí)別
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    // SERIALIZABLE 隔離級(jí)別
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    // 默認(rèn)超時(shí)時(shí)間
    int TIMEOUT_DEFAULT = -1;
    // 獲取事物傳播特性
    int getPropagationBehavior();
    // 獲取事物隔離級(jí)別
    int getIsolationLevel();
    // 獲取事物超時(shí)時(shí)間
    int getTimeout();
    // 判斷事物是否可讀
    boolean isReadOnly();
    // 獲取事物名稱
    @Nullable
    String getName();
}
  • Spring事物傳播特性表:
傳播特性名稱說(shuō)明
PROPAGATION_REQUIRED如果當(dāng)前沒(méi)有事物,則新建一個(gè)事物;如果已經(jīng)存在一個(gè)事物,則加入到這個(gè)事物中
PROPAGATION_SUPPORTS支持當(dāng)前事物,如果當(dāng)前沒(méi)有事物,則以非事物方式執(zhí)行
PROPAGATION_MANDATORY使用當(dāng)前事物,如果當(dāng)前沒(méi)有事物,則拋出異常
PROPAGATION_REQUIRES_NEW新建事物,如果當(dāng)前已經(jīng)存在事物,則掛起當(dāng)前事物
PROPAGATION_NOT_SUPPORTED以非事物方式執(zhí)行,如果當(dāng)前存在事物,則掛起當(dāng)前事物
PROPAGATION_NEVER以非事物方式執(zhí)行,如果當(dāng)前存在事物,則拋出異常
PROPAGATION_NESTED如果當(dāng)前存在事物,則在嵌套事物內(nèi)執(zhí)行;如果當(dāng)前沒(méi)有事物,則與PROPAGATION_REQUIRED傳播特性相同
  • Spring事物隔離級(jí)別表:
事務(wù)隔離級(jí)別臟讀不可重復(fù)讀幻讀
讀未提交(read-uncommitted)
不可重復(fù)讀(read-committed)
可重復(fù)讀(repeatable-read)
串行化(serializable)

MySQL默認(rèn)的事務(wù)隔離級(jí)別為 可重復(fù)讀repeatable-read

PlatformTransactionManager-->Spring事務(wù)基礎(chǔ)結(jié)構(gòu)中的中心接口

public interface PlatformTransactionManager {
    // 根據(jù)指定的傳播行為,返回當(dāng)前活動(dòng)的事務(wù)或創(chuàng)建新事務(wù)。
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    // 就給定事務(wù)的狀態(tài)提交給定事務(wù)。
    void commit(TransactionStatus status) throws TransactionException;
    // 執(zhí)行給定事務(wù)的回滾。
    void rollback(TransactionStatus status) throws TransactionException;
}

Spring將事物管理委托給底層的持久化框架來(lái)完成,因此,Spring為不同的持久化框架提供了不同的PlatformTransactionManager接口實(shí)現(xiàn)。列舉幾個(gè)Spring自帶的事物管理器:

事物管理器說(shuō)明
org.springframework.jdbc.datasource.DataSourceTransactionManager提供對(duì)單個(gè)javax.sql.DataSource事務(wù)管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事務(wù)管理
org.springframework.orm.jpa.JpaTransactionManager提供對(duì)單個(gè)javax.persistence.EntityManagerFactory事務(wù)支持,用于集成JPA實(shí)現(xiàn)框架時(shí)的事務(wù)管理
org.springframework.transaction.jta.JtaTransactionManager提供對(duì)分布式事務(wù)管理的支持,并將事務(wù)管理委托給Java EE應(yīng)用服務(wù)器事務(wù)管理器
  • TransactionStatus-->事物狀態(tài)描述
  • TransactionStatus接口
public interface TransactionStatus extends SavepointManager, Flushable {
    // 返回當(dāng)前事務(wù)是否為新事務(wù)(否則將參與到現(xiàn)有事務(wù)中,或者可能一開(kāi)始就不在實(shí)際事務(wù)中運(yùn)行)
    boolean isNewTransaction();
    // 返回該事務(wù)是否在內(nèi)部攜帶保存點(diǎn),也就是說(shuō),已經(jīng)創(chuàng)建為基于保存點(diǎn)的嵌套事務(wù)。
    boolean hasSavepoint();
    // 設(shè)置事務(wù)僅回滾。
    void setRollbackOnly();
    // 返回事務(wù)是否已標(biāo)記為僅回滾
    boolean isRollbackOnly();
    // 將會(huì)話刷新到數(shù)據(jù)存儲(chǔ)區(qū)
    @Override
    void flush();
    // 返回事物是否已經(jīng)完成,無(wú)論提交或者回滾。
    boolean isCompleted();
}
  • SavepointManager接口
public interface SavepointManager {
    // 創(chuàng)建一個(gè)新的保存點(diǎn)。
    Object createSavepoint() throws TransactionException;
    // 回滾到給定的保存點(diǎn)。
    // 注意:調(diào)用此方法回滾到給定的保存點(diǎn)之后,不會(huì)自動(dòng)釋放保存點(diǎn),
    // 可以通過(guò)調(diào)用releaseSavepoint方法釋放保存點(diǎn)。
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    // 顯式釋放給定的保存點(diǎn)。(大多數(shù)事務(wù)管理器將在事務(wù)完成時(shí)自動(dòng)釋放保存點(diǎn))
    void releaseSavepoint(Object savepoint) throws TransactionException;
}

Spring編程式事物

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `balance` int(11) DEFAULT NULL COMMENT '賬戶余額',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='--賬戶表'
  • 實(shí)現(xiàn)
import org.apache.commons.dbcp.BasicDataSource;
 import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.DefaultTransactionDefinition;
 import javax.sql.DataSource;
 public class MyTransaction {
     private JdbcTemplate jdbcTemplate;
     private DataSourceTransactionManager txManager;
     private DefaultTransactionDefinition txDefinition;
     private String insert_sql = "insert into account (balance) values ('100')";
     public void save() {
         // 1、初始化jdbcTemplate
         DataSource dataSource = getDataSource();
         jdbcTemplate = new JdbcTemplate(dataSource);
         // 2、創(chuàng)建物管理器
         txManager = new DataSourceTransactionManager();
         txManager.setDataSource(dataSource);
         // 3、定義事物屬性
         txDefinition = new DefaultTransactionDefinition();
         txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
         // 3、開(kāi)啟事物
         TransactionStatus txStatus = txManager.getTransaction(txDefinition);
         // 4、執(zhí)行業(yè)務(wù)邏輯
         try {
             jdbcTemplate.execute(insert_sql);
             //int i = 1/0;
             jdbcTemplate.execute(insert_sql);
             txManager.commit(txStatus);
         } catch (DataAccessException e) {
             txManager.rollback(txStatus);
             e.printStackTrace();
         }
     }
     public DataSource getDataSource() {
         BasicDataSource dataSource = new BasicDataSource();
         dataSource.setDriverClassName("com.mysql.jdbc.Driver");
         dataSource.setUrl("jdbc:mysql://localhost:3306/my_test?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
         dataSource.setUsername("root");
         dataSource.setPassword("dabin1991@");
         return dataSource;
     }
 }
  • 測(cè)試類(lèi)及結(jié)果
public class MyTest {
    @Test
    public void test1() {
        MyTransaction myTransaction = new MyTransaction();
        myTransaction.save();
    }
}

運(yùn)行測(cè)試類(lèi),在拋出異常之后手動(dòng)回滾事物,所以數(shù)據(jù)庫(kù)表中不會(huì)增加記錄。

基于@Transactional注解的聲明式事物

其底層建立在 AOP 的基礎(chǔ)之上,對(duì)方法前后進(jìn)行攔截,然后在目標(biāo)方法開(kāi)始之前創(chuàng)建或者加入一個(gè)事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。通過(guò)聲明式事物,無(wú)需在業(yè)務(wù)邏輯代碼中摻雜事務(wù)管理的代碼,只需在配置文件中做相關(guān)的事務(wù)規(guī)則聲明(或通過(guò)等價(jià)的基于標(biāo)注的方式),便可以將事務(wù)規(guī)則應(yīng)用到業(yè)務(wù)邏輯中。

  • 接口
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Transactional(propagation = Propagation.REQUIRED)
public interface AccountServiceImp {
    void save() throws RuntimeException;
}
  • 實(shí)現(xiàn)
import org.springframework.jdbc.core.JdbcTemplate;
public class AccountServiceImpl implements AccountServiceImp {
    private JdbcTemplate jdbcTemplate;
    private static String insert_sql = "insert into account(balance) values (100)";
    @Override
    public void save() throws RuntimeException {
        System.out.println("==開(kāi)始執(zhí)行sql");
        jdbcTemplate.update(insert_sql);
        System.out.println("==結(jié)束執(zhí)行sql");
        System.out.println("==準(zhǔn)備拋出異常");
        throw new RuntimeException("==手動(dòng)拋出一個(gè)異常");
    }
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}
  • 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--開(kāi)啟tx注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!--事物管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--數(shù)據(jù)源-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/my_test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="dabin1991@"/>
    </bean>

    <!--jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--業(yè)務(wù)bean-->
    <bean id="accountService" class="com.dabin.aop.AccountServiceImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

</beans>
  • 測(cè)試
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void test1() {
        // 基于tx標(biāo)簽的聲明式事物
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
        AccountServiceImp studentService = ctx.getBean("accountService", AccountServiceImp.class);
        studentService.save();
    }
}
  • 測(cè)試

==開(kāi)始執(zhí)行sql
==結(jié)束執(zhí)行sql
==準(zhǔn)備拋出異常

java.lang.RuntimeException: ==手動(dòng)拋出一個(gè)異常

    at com.lyc.cn.v2.day09.AccountServiceImpl.save(AccountServiceImpl.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

測(cè)試方法中手動(dòng)拋出了一個(gè)異常,Spring會(huì)自動(dòng)回滾事物,查看數(shù)據(jù)庫(kù)可以看到并沒(méi)有新增記錄。

注意:默認(rèn)情況下Spring中的事務(wù)處理只對(duì)RuntimeException方法進(jìn)行回滾,所以,如果此處將RuntimeException替換成普通的Exception不會(huì)產(chǎn)生回滾效果。

后面在分析基于@Transactional注解的聲明式事物的的源碼實(shí)現(xiàn),

以上就是Spring @Transactional注解的聲明式事務(wù)簡(jiǎn)化業(yè)務(wù)邏輯中的事務(wù)管理的詳細(xì)內(nèi)容,更多關(guān)于Spring @Transactiona聲明式事務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Idea2020 無(wú)法share項(xiàng)目到svn的解決方法

    Idea2020 無(wú)法share項(xiàng)目到svn的解決方法

    這篇文章主要介紹了Idea2020 無(wú)法share項(xiàng)目到svn的解決方法,需要的朋友可以參考下
    2020-09-09
  • JVM的類(lèi)加載過(guò)程以及雙親委派模型詳解

    JVM的類(lèi)加載過(guò)程以及雙親委派模型詳解

    這篇文章主要介紹了JVM的類(lèi)加載過(guò)程以及雙親委派模型詳解,類(lèi)加載器就是根據(jù)指定全限定名稱將 class 文件加載到 JVM 內(nèi)存,然后再轉(zhuǎn)化為 class 對(duì)象。,需要的朋友可以參考下
    2019-06-06
  • Hashmap非線程安全關(guān)于hash值沖突處理

    Hashmap非線程安全關(guān)于hash值沖突處理

    這篇文章主要為大家介紹了Hashmap非線程安全關(guān)于hash值沖突的處理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • Java 動(dòng)態(tài)加載jar和class文件實(shí)例解析

    Java 動(dòng)態(tài)加載jar和class文件實(shí)例解析

    這篇文章主要介紹了Java 動(dòng)態(tài)加載jar和class文件實(shí)例解析,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • mybatisplus之使用@Select解讀

    mybatisplus之使用@Select解讀

    這篇文章主要介紹了mybatisplus之使用@Select解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java將文件上傳到ftp服務(wù)器

    Java將文件上傳到ftp服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了Java將文件上傳到ftp服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Spring注解之@PropertySource詳解

    Spring注解之@PropertySource詳解

    這篇文章主要介紹了Spring注解之@PropertySource詳解,@PropertySource注解用于指定資源文件讀取的位置,它不僅能讀取properties文件,也能讀取xml文件,并且通過(guò)YAML解析器,配合自定義PropertySourceFactory實(shí)現(xiàn)解析YAML文件,需要的朋友可以參考下
    2023-11-11
  • Sentinel熱門(mén)詞匯限流的實(shí)現(xiàn)詳解

    Sentinel熱門(mén)詞匯限流的實(shí)現(xiàn)詳解

    這篇文章主要介紹了使用Sentinel對(duì)熱門(mén)詞匯進(jìn)行限流的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java基礎(chǔ)之打印萬(wàn)年歷的簡(jiǎn)單實(shí)現(xiàn)(案例)

    Java基礎(chǔ)之打印萬(wàn)年歷的簡(jiǎn)單實(shí)現(xiàn)(案例)

    下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)之打印萬(wàn)年歷的簡(jiǎn)單實(shí)現(xiàn)(案例)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • 輕松掌握J(rèn)ava代理模式

    輕松掌握J(rèn)ava代理模式

    這篇文章主要幫助大家輕松掌握J(rèn)ava代理模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09

最新評(píng)論