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

Spring源碼解析之編程式事務(wù)

 更新時(shí)間:2021年06月10日 16:58:54   作者:星夜孤帆  
今天給大家?guī)?lái)的是關(guān)于Java Spring的相關(guān)知識(shí),文章圍繞著Spring編程式事務(wù)展開(kāi),文中有非常詳細(xì)的介紹,需要的朋友可以參考下

一、前言

在Spring中,事務(wù)有兩種實(shí)現(xiàn)方式:

編程式事務(wù)管理: 編程式事務(wù)管理使用TransactionTemplate可實(shí)現(xiàn)更細(xì)粒度的事務(wù)控制。聲明式事務(wù)管理: 基于Spring AOP實(shí)現(xiàn)。其本質(zhì)是對(duì)方法前后進(jìn)行攔截,然后在目標(biāo)方法開(kāi)始之前創(chuàng)建或者加入一個(gè)事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。

聲明式事務(wù)管理不需要入侵代碼,通過(guò)@Transactional就可以進(jìn)行事務(wù)操作,更快捷而且簡(jiǎn)單(尤其是配合spring boot自動(dòng)配置,可以說(shuō)是精簡(jiǎn)至極!),且大部分業(yè)務(wù)都可以滿(mǎn)足,推薦使用。

其實(shí)不管是編程式事務(wù)還是聲明式事務(wù),最終調(diào)用的底層核心代碼是一致的。本文主要介紹編程式事務(wù)的一些應(yīng)用,以及獨(dú)有的源碼分析,再在其他文章中進(jìn)入核心源碼貫穿式講解。

二、編程式事務(wù)解析

編程式事務(wù),Spring已經(jīng)給我們提供好了模板類(lèi)TransactionTemplate,可以很方便的使用,如下圖:

TransactionTemplate全路徑名是:org.springframework.transaction.support.TransactionTemplate??窗仓懒诉@是spring對(duì)事務(wù)的模板類(lèi)。(spring動(dòng)不動(dòng)就是各種Template...),看下類(lèi)圖先:

實(shí)現(xiàn)了TransactionOperations、InitializingBean這2個(gè)接口(熟悉spring源碼的知道這個(gè)InitializingBean又是老套路),我們來(lái)看下接口源碼如下:

public interface TransactionOperations {
 
	@Nullable
	<T> T execute(TransactionCallback<T> action) throws TransactionException;
 
}
 
public interface InitializingBean {
 
	void afterPropertiesSet() throws Exception;
 
}

如上圖,TransactionOperations這個(gè)接口用來(lái)執(zhí)行事務(wù)的回調(diào)方法,InitializingBean這個(gè)是典型的spring bean初始化流程中的預(yù)留接口,專(zhuān)用用來(lái)在bean屬性加載完畢時(shí)執(zhí)行的方法。

回到正題,TransactionCallback和TransactionCallbackWithoutResult做了什么

@FunctionalInterface
public interface TransactionCallback<T> {
 
	@Nullable
	T doInTransaction(TransactionStatus status);
 
}
 
 
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
 
	@Override
	@Nullable
	public final Object doInTransaction(TransactionStatus status) {
		doInTransactionWithoutResult(status);
		return null;
	}
 
	protected abstract void doInTransactionWithoutResult(TransactionStatus status);
 
}

可見(jiàn)TransactionCallbackWithResult實(shí)現(xiàn)了TransactionCallback接口,重寫(xiě)了doIntransaction方法,在內(nèi)部調(diào)用了doInTransactionWithoutResult方法,幫我們返回了null,所以,我們就不需要再指定返回值了。 

TransactionTemplate的2個(gè)接口的impl方法做了什么?

@Override
    public void afterPropertiesSet() {
        if (this.transactionManager == null) {
            throw new IllegalArgumentException("Property 'transactionManager' is required");
        }
    }
 
 
    @Override
    public <T> T execute(TransactionCallback<T> action) throws TransactionException {       // 內(nèi)部封裝好的事務(wù)管理器
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
        }// 需要手動(dòng)獲取事務(wù),執(zhí)行方法,提交事務(wù)的管理器
        else {// 1.獲取事務(wù)狀態(tài)
            TransactionStatus status = this.transactionManager.getTransaction(this);
            T result;
            try {// 2.執(zhí)行業(yè)務(wù)邏輯
                result = action.doInTransaction(status);
            }
            catch (RuntimeException ex) {
                // 應(yīng)用運(yùn)行時(shí)異常 -> 回滾
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Error err) {
                // Error異常 -> 回滾
                rollbackOnException(status, err);
                throw err;
            }
            catch (Throwable ex) {
                // 未知異常 -> 回滾
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }// 3.事務(wù)提交
            this.transactionManager.commit(status);
            return result;
        }
    }

如上圖所示,實(shí)際上afterPropertiesSet只是校驗(yàn)了事務(wù)管理器不為空,execute()才是核心方法,execute主要步驟:

1.getTransaction()獲取事務(wù)

2.doInTransaction()執(zhí)行業(yè)務(wù)邏輯,這里就是用戶(hù)自定義的業(yè)務(wù)代碼。如果是沒(méi)有返回值的,就是doInTransactionWithoutResult()。

3.commit()事務(wù)提交:調(diào)用AbstractPlatformTransactionManager的commit,rollbackOnException()異?;貪L:調(diào)用AbstractPlatformTransactionManager的rollback(),事務(wù)提交回滾。源碼見(jiàn)后續(xù)文章

三、編程式事務(wù)示例

public class SpringTransactionExample {
 
    private static String url = "jdbc:mysql://localhost:3306/spring_transaction?useSSL=false&characterEncoding=utf-8&autoReconnect=true";
    private static String user = "root";
    private static String password = "root";
 
    public static void main(String[] args) {
        // 獲取數(shù)據(jù)源
        final DataSource ds = new DriverManagerDataSource(url, user, password);
        // 編程式事務(wù)
        final TransactionTemplate template = new TransactionTemplate();
        // 設(shè)置事務(wù)管理器
        template.setTransactionManager(new DataSourceTransactionManager(ds));
 
        template.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                Connection conn = DataSourceUtils.getConnection(ds);
                Object savePoint = null;
                try {
                    {
                        // 插入
                        PreparedStatement prepare = conn.prepareStatement("insert into person(id, name) values (?, ?)");
                        prepare.setString(1, "1");
                        prepare.setString(2, "1111");
                        prepare.executeUpdate();
                    }
 
                    // 設(shè)置保存點(diǎn),回滾的化,不會(huì)回滾保存點(diǎn)之前的操作
                    savePoint = transactionStatus.createSavepoint();
                    {
                        // 插入
                        PreparedStatement prepare = conn.prepareStatement("insert into person(id, name) values (?, ?)");
                        prepare.setString(1, "2");
                        prepare.setString(2, "222");
                        prepare.executeUpdate();
                    }
 
                    {
                        // 更新
                        PreparedStatement prepare = conn.prepareStatement("update person set name = ? where id = ?");
                        prepare.setString(1, "jak");
                        prepare.setInt(2, 6);
                        prepare.executeUpdate();
 
                        // 模擬異常
//                        int i = 1 / 0;
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    System.out.println("更新失敗");
                    if (savePoint != null) {
                        // 回滾到保存點(diǎn)
                        transactionStatus.rollbackToSavepoint(savePoint);
                    } else {
                        transactionStatus.setRollbackOnly();
                    }
                }
                return null;
            }
        });
    }
}

四、TransactionCallback

編程式事務(wù)帶返回值

public class TransactionCallBackTest {
    private static String url = "jdbc:mysql://localhost:3306/spring_transaction?useSSL=false&characterEncoding=utf-8&autoReconnect=true";
    private static String user = "root";
    private static String password = "root";
 
    public static void main(String[] args) {
        // 獲取數(shù)據(jù)源
        final DataSource ds = new DriverManagerDataSource(url, user, password);
        // 編程式事務(wù)
        final TransactionTemplate template = new TransactionTemplate();
        // 設(shè)置事務(wù)管理器
        template.setTransactionManager(new DataSourceTransactionManager(ds));
        Connection connection = DataSourceUtils.getConnection(ds);
        test1(template, connection);
        test2(template, connection);
    }
 
    // 方式一: 匿名內(nèi)部類(lèi)
    @SuppressWarnings("all")
    public static void test1(TransactionTemplate template,  Connection connection) {
        // TransactionCallback有返回值
        template.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                try {
                    // 插入
                    PreparedStatement prepare = connection.prepareStatement("insert into person(id, name) values (?, ?)");
                    prepare.setInt(1, 1);
                    prepare.setString(2, "jak");
                    prepare.executeUpdate();
                    // 模擬異常
                    // int i = 1 / 0;
                    System.out.println("數(shù)據(jù)已插入");
                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    System.out.println("更新失敗");
                    status.setRollbackOnly();
                }
                return null;
            }
        });
    }
 
    // 方式二:lamda表達(dá)式
    @SuppressWarnings("all")
    public static void test2(TransactionTemplate template,  Connection connection) {
        template.execute((status) -> {
            try {
                // 插入
                PreparedStatement prepare = connection.prepareStatement("insert into person(id, name) values (?, ?)");
                prepare.setInt(1, 2);
                prepare.setString(2, "hyd");
                prepare.executeUpdate();
                // 模擬異常
                // int i = 1 / 0;
                System.out.println("數(shù)據(jù)已插入");
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (Exception e) {
                System.out.println("更新失敗");
                status.setRollbackOnly();
            }
            return null;
        });
    }
 
}

五、TransactionCallbackWithoutResult

編程式事務(wù)不帶返回值

public class TransactionCallbackWithoutResultTest {
 
    private static String url = "jdbc:mysql://localhost:3306/spring_transaction?useSSL=false&characterEncoding=utf-8&autoReconnect=true";
    private static String user = "root";
    private static String password = "root";
 
    @SuppressWarnings("all")
    public static void test(TransactionTemplate template, Connection connection) {
        template.execute(new TransactionCallbackWithoutResult() {
            // doInTransactionWithoutResult無(wú)返回值
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 插入
                    PreparedStatement prepare = connection.prepareStatement("insert into person(id, name) values (?, ?)");
                    prepare.setInt(1, 1);
                    prepare.setString(2, "jak");
                    prepare.executeUpdate();
                    // 模擬異常
                    // int i = 1 / 0;
                    System.out.println("數(shù)據(jù)已插入");
                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    System.out.println("更新失敗");
                    status.setRollbackOnly();
                }
            }
        });
    }
 
    public static void main(String[] args) {
        // 獲取數(shù)據(jù)源
        final DataSource ds = new DriverManagerDataSource(url, user, password);
        // 編程式事務(wù)
        final TransactionTemplate template = new TransactionTemplate();
        // 設(shè)置事務(wù)管理器
        template.setTransactionManager(new DataSourceTransactionManager(ds));
        Connection connection = DataSourceUtils.getConnection(ds);
        test(template, connection);
    }
}

踩坑指南,上述方式 不知道為啥,事務(wù)一直不回滾,改為jdbcTemplate方式,可以正?;貪L,不知道什么原因

public class jdbcTemplateTest {
 
    private static String url = "jdbc:mysql://localhost:3306/spring_transaction?useSSL=false&characterEncoding=utf-8&autoReconnect=true";
    private static String user = "root";
    private static String password = "root";
 
    @SuppressWarnings("all")
    public static void test(TransactionTemplate template,  JdbcTemplate jdbcTemplate) {
        template.execute(new TransactionCallbackWithoutResult() {
            // doInTransactionWithoutResult無(wú)返回值
            @SneakyThrows
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 插入
                    jdbcTemplate.execute("insert into person(id, name) values (2, 'jak')");
                    // 模擬異常
                    int i = 1 / 0;
                    System.out.println("數(shù)據(jù)已插入");
                } catch (Exception e) {
                    // 標(biāo)記事務(wù)回滾
                    status.setRollbackOnly();
                }
            }
        });
    }
 
    public static void main(String[] args) {
        // 獲取數(shù)據(jù)源
        final DataSource ds = new DriverManagerDataSource(url, user, password);
        // 編程式事務(wù)
        final TransactionTemplate template = new TransactionTemplate();
        // jdbcTemplate
        final JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 設(shè)置事務(wù)管理器
        template.setTransactionManager(new DataSourceTransactionManager(ds));
        // 配置數(shù)據(jù)源
        jdbcTemplate.setDataSource(ds);
        test(template,  jdbcTemplate);
    }
}

參考文章、參考文章

到此這篇關(guān)于Spring源碼解析之編程式事務(wù)的文章就介紹到這了,更多相關(guān)Spring編程式事務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 利用Java快速查找21位花朵數(shù)示例代碼

    利用Java快速查找21位花朵數(shù)示例代碼

    這篇文章主要給大家介紹了關(guān)于利用Java快速查找21位花朵數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • 教你怎么用Java開(kāi)發(fā)掃雷游戲

    教你怎么用Java開(kāi)發(fā)掃雷游戲

    我們那時(shí)候上機(jī)經(jīng)常玩掃雷,試想如果我當(dāng)年可以用 java 寫(xiě)個(gè)掃雷出來(lái),那場(chǎng)面不用我多說(shuō)了吧,大家讓開(kāi),我要開(kāi)始裝逼了,之前用JavaScript寫(xiě)過(guò)了一個(gè)掃雷,這次我用java再寫(xiě)了一遍,權(quán)當(dāng)是復(fù)習(xí)咯.文中有非常詳細(xì)的代碼示例,需要的朋友可以參考下
    2021-05-05
  • 基于Zookeeper實(shí)現(xiàn)服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能

    基于Zookeeper實(shí)現(xiàn)服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能

    無(wú)論是采用SOA還是微服務(wù)架構(gòu),都需要使用服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)組件,本文將基于 Zookeeper 實(shí)現(xiàn)服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)功能,如果跟我一樣有同樣的困惑,希望可以通過(guò)本文了解其他組件如何使用 Zookeeper 作為注冊(cè)中心的工作原理
    2023-09-09
  • Swing拆分窗格控件JSplitPane使用詳解

    Swing拆分窗格控件JSplitPane使用詳解

    這篇文章主要為大家詳細(xì)介紹了Swing拆分窗格控件JSplitPane的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java反射(JDK)與動(dòng)態(tài)代理(CGLIB)詳解

    Java反射(JDK)與動(dòng)態(tài)代理(CGLIB)詳解

    下面小編就為大家?guī)?lái)一篇淺談Java反射與動(dòng)態(tài)代理。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-08-08
  • SpringBoot項(xiàng)目啟動(dòng)錯(cuò)誤:找不到或無(wú)法加載主類(lèi)的幾種解決方法

    SpringBoot項(xiàng)目啟動(dòng)錯(cuò)誤:找不到或無(wú)法加載主類(lèi)的幾種解決方法

    本文主要介紹了SpringBoot項(xiàng)目啟動(dòng)錯(cuò)誤:找不到或無(wú)法加載主類(lèi)的幾種解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-03-03
  • Spring MVC @GetMapping和@PostMapping注解的使用方式

    Spring MVC @GetMapping和@PostMapping注解的使用方式

    這篇文章主要介紹了Spring MVC @GetMapping和@PostMapping注解的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java多線程揭秘之synchronized工作原理

    Java多線程揭秘之synchronized工作原理

    synchronized算是多線程中非常常用的加鎖方式了,但很多人都不太理解其底層的工作原理。本篇文章博主用盡可能通俗易懂的方式來(lái)帶大家去看看synchronized究竟是怎么加鎖的
    2021-10-10
  • Java實(shí)現(xiàn)FIFO、LRU、LFU、OPT頁(yè)面置換算法

    Java實(shí)現(xiàn)FIFO、LRU、LFU、OPT頁(yè)面置換算法

    本文主要介紹了Java實(shí)現(xiàn)FIFO、LRU、LFU、OPT頁(yè)面置換算法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Mybatis-Plus中的@TableName 和 table-prefix使用

    Mybatis-Plus中的@TableName 和 table-prefix使用

    table-prefix 是一個(gè)全局配置,它會(huì)自動(dòng)在所有表名前添加指定的前綴,這個(gè)配置對(duì)于那些使用一致命名約定的數(shù)據(jù)庫(kù)表非常有用,這篇文章主要介紹了Mybatis-Plus中的@TableName 和 table-prefix使用,需要的朋友可以參考下
    2024-08-08

最新評(píng)論

两当县| 奉新县| 洛浦县| 上饶县| 开封市| 双峰县| 上饶县| 天柱县| 鄂伦春自治旗| 米易县| 华坪县| 云浮市| 洱源县| 华安县| 名山县| 岳普湖县| 玉溪市| 商丘市| 三亚市| 闸北区| 高青县| 渑池县| 汉川市| 盐源县| 宜川县| 六枝特区| 唐山市| 延边| 永靖县| 江安县| 万州区| 台前县| 繁昌县| 抚宁县| 庆安县| 西乌| 德江县| 湘潭市| 黄大仙区| 阜城县| 临桂县|