大數據

Spring 5 中文解析數據存儲篇-編程式事物管理

Spring核心篇章:

Spring 5 中文解析之核心篇-IoC容器

Spring 5 中文解析核心篇-IoC容器之依賴關係

Spring 5 中文解析核心篇-IoC容器之Bean作用域

Spring 5 中文解析核心篇-IoC容器之自定義Bean性質

Spring 5 中文解析核心篇-IoC容器之BeanDefinition繼承與容器拓展點

Spring 5 中文解析核心篇-IoC容器之基於註解的容器配置

Spring 5 中文解析核心篇-IoC容器之類路徑掃描和組件管理

Spring 5 中文解析核心篇-IoC容器之JSR330標準註解

Spring 5 中文解析核心篇-IoC容器之基於Java容器配置

Spring 5 中文解析核心篇-IoC容器之Environment抽象

Spring 5 中文解析核心篇-IoC容器之ApplicationContext與BeanFactory

Spring 5 中文解析核心篇-IoC容器之Resources

Spring 5 中文解析核心篇-IoC容器之數據校驗、數據綁定和類型轉換

Spring 5 中文解析核心篇-IoC容器之SpEL表達式

Spring 5 中文解析核心篇-IoC容器之AOP編程(上)")

Spring 5 中文解析核心篇-IoC容器之AOP編程(下)")

Spring 5 中文解析核心篇-IoC容器之Spring AOP API

Spring測試篇章:

Spring 5 中文解析測試篇-Spring測試

Spring 5 中文解析核心篇-集成測試之概要和集成測試註解

Spring 5 中文解析核心篇-集成測試之TestContext(上)")

Spring 5 中文解析核心篇-集成測試之TestContext(中)")

Spring 5 中文解析測試篇-集成測試之TestContext(下)")

Spring 5 中文解析測試篇-Spring MVC測試框架

Spring 5 中文解析測試篇-WebTestClient

Spring存儲篇章:

Spring 5 中文解析數據存儲篇-Spring框架的事物支持模型的優勢

[Spring 5 中文解析數據存儲篇-事務同步和聲明式事物管理
](https://mp.weixin.qq.com/s?__biz=MzA3NDgzODYzNg==&tempkey=MTA3OV91TU8vcGlxSXdvTGNhZ2o0a3p2RXZvSGpJeXNCMmNCUkszbU9OZzVSc09rT19Zejl6b3JCWHZHU0JfN3ZrVDhhbzZUV3BfS2s3aHFEakhPb3V4dXVkMVp4ajFfZllOcnM2N3huU2d1ZUJZZlN6T1lZNVVKWHJjOWRkdEg3Uzg3RmpFRzZXbHMzQ3lFUUEwd1JqTl9JOGZzWGxMYWh6N1lhY05DYnFRfn4%3D&chksm=1f7b0caa280c85bcce8c4ffe9fb21629f683d5d9127116dae91dc9b9cbd2f367a19514fef76f#rd)

[Spring 5 中文解析數據存儲篇-@Transactional使用
](https://mp.weixin.qq.com/s?__biz=MzA3NDgzODYzNg==&tempkey=MTA3OV9RNU1VNnhsa0ZkRlhBb3Fla3p2RXZvSGpJeXNCMmNCUkszbU9OZzVSc09rT19Zejl6b3JCWHZHU0JfNTZ4dWhENjFrNUV6dlpieWYxVndQRlBNNkFRZVBFWlVyZHdiQlhTMmZMM0g0TnppT040Nk5QUU1rcEpNY2FDN09nZnNPeG5WTU8wajZCNUowaHZnTHhZcGpYdVRlNXQzWTZUSV8yOEpJNl9nfn4%3D&chksm=1f7b0cb3280c85a5682b1c9ea3cf7d2a69abdd6fe9147ed4335a5d5cfbef7c04ed314bd389de#rd)

完整電子書地址

Spring框架通過使用以下兩種方式提供編程式事務管理的方法:

  • TransactionTemplateTransactionalOperator
  • TransactionManager直接實現

Spring團隊通常建議對命令式流程中的編程式事務管理推薦使用TransactionTemplate,對響應性代碼推薦TransactionalOperator。第二種方法類似於使用JTA UserTransaction API,儘管異常處理的麻煩程度較小。

1.5.1 使用TransactionTemplate

TransactionTemplate採用與其他Spring模板(如JdbcTemplate)相同的方法。它使用一種回調方法(使應用程序代碼不必進行樣板獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。

如下面的示例所示,使用TransactionTemplate完全將你與Spring的事務基礎結構和api結合在一起。編程式事務管理是否適合你的開發需求是你必須自己做的決定。

必須在事務上下文中運行並且顯式使用TransactionTemplate的應用程序代碼類似於下一個示例。作為應用程序開發人員,你可以編寫TransactionCallback實現(通常表示為匿名內部類),其中包含你需要在事務上下文中運行的代碼。然後,你可以將自定義TransactionCallback的實例傳遞給TransactionTemplate上暴露的execute(..)方法。以下示例顯示瞭如何執行此操作:

public class SimpleService implements Service {

    // single TransactionTemplate shared amongst all methods in this instance
    private final TransactionTemplate transactionTemplate;

    // use constructor-injection to supply the PlatformTransactionManager
    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }

    public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {
            // the code in this method runs in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }
}

如果沒有返回值,則可以將便捷的TransactionCallbackWithoutResult類與匿名類一起使用,如下所示:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        updateOperation1();
        updateOperation2();
    }
});

回調中的代碼可以通過在提供的TransactionStatus對象上調用setRollbackOnly()方法來回滾事務,如下所示:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
            updateOperation1();
            updateOperation2();
        } catch (SomeBusinessException ex) {
            status.setRollbackOnly();
        }
    }
});

指定事物配置

你可以通過編程方式或配置方式在TransactionTemplate上指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionTemplate實例具有默認的事務設置。以下示例顯示了針對特定TransactionTemplate的事務設置的編程自定義:

public class SimpleService implements Service {

    private final TransactionTemplate transactionTemplate;

    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired
        this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        this.transactionTemplate.setTimeout(30); // 30 seconds
        // and so forth...
    }
}

以下示例通過使用Spring XML配置來定義帶有一些自定義事務設置的TransactionTemplate

<bean id="sharedTransactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
    <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
    <property name="timeout" value="30"/>
</bean>

然後,你可以將sharedTransactionTemplate注入到所需的服務中。

最後,TransactionTemplate類的實例是線程安全的,因為這些實例不維護任何對話狀態。但是,TransactionTemplate實例確實會維護配置狀態。因此,儘管許多類可以共享一個TransactionTemplate實例,但是如果一個類需要使用具有不同設置(例如,不同的隔離級別)的TransactionTemplate,則需要創建兩個不同的TransactionTemplate實例。

參考代碼:org.liyong.dataaccess.starter.TransactionTemplateIocContainer

1.5.2 使用TransactionOperator

TransactionOperator遵循類似於其他響應式操作符的設計。它使用一種回調方法(使應用程序代碼不必進行模版獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。

如以下示例所示,使用TransactionOperator絕對可以使你與Spring的事務基礎結構和API結合。編程式事務管理是否適合你的開發需求是你必須自己做的決定。

必須在事務上下文中運行並且顯式使用TransactionOperator的應用程序代碼類似於下一個示例:

public class SimpleService implements Service {

    // single TransactionOperator shared amongst all methods in this instance
    private final TransactionalOperator transactionalOperator;

    // use constructor-injection to supply the ReactiveTransactionManager
    public SimpleService(ReactiveTransactionManager transactionManager) {
        this.transactionOperator = TransactionalOperator.create(transactionManager);
    }

    public Mono<Object> someServiceMethod() {

        // the code in this method runs in a transactional context

        Mono<Object> update = updateOperation1();

        return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
    }
}

TransactionalOperator可以通過兩種方式使用:

  • 使用Reactor類型的操作符樣式(mono.as(transactionalOperator :: transactional))
  • 其他所有情況的回調樣式(transactionalOperator.execute(TransactionCallback <T>))

回調中的代碼可以通過在提供的ReactiveTransaction對象上調用setRollbackOnly()方法來回滾事務,如下所示:

transactionalOperator.execute(new TransactionCallback<>() {

    public Mono<Object> doInTransaction(ReactiveTransaction status) {
        return updateOperation1().then(updateOperation2)
                    .doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
        }
    }
});

取消信號

在響應式流中,Subscriber可以取消其Subscription並停止其PublisherProject Reactor以及其他庫中的操作符,例如next()take(long)timeout(Duration)等,都可以發出取消操作。沒有辦法知道取消的原因,無論是由於錯誤還是僅僅是出於進一步消費的興趣,並且在5.2版中,TransactionalOperator默認在取消時提交事務。在版本5.3中,這種行為將發生改變,事務將在取消時回滾,以創建可靠的和確定性的結果。因此,重要的是要考慮從事務發佈服務器下游使用的操作符。特別是在Flux或其他多值Publisher的情況下,必須使用完整的輸出以允許事務完成。

指定事物配置

你可以為TransactionalOperator指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionalOperator實例具有默認的事務設置。以下示例顯示了針對特定TransactionalOperator的事務設置的自定義:

public class SimpleService implements Service {

    private final TransactionalOperator transactionalOperator;

    public SimpleService(ReactiveTransactionManager transactionManager) {
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();

        // the transaction settings can be set here explicitly if so desired
        definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        definition.setTimeout(30); // 30 seconds
        // and so forth...

        this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
    }
}
1.5.3 使用TransactionManager

以下各節說明命令式和響應式事務管理器的用法。

使用PlatformTransactionManager

對於命令式事務,可以直接使用org.springframework.transaction.PlatformTransactionManager來管理事務。為此,通過bean引用將你使用的PlatformTransactionManager的實現傳遞給bean。然後,通過使用TransactionDefinitionTransactionStatus對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    // put your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

使用ReactiveTransactionManager

使用響應式事務時,可以直接使用org.springframework.transaction.ReactiveTransactionManager來管理事務。為此,請通過bean引用將你使用的ReactiveTransactionManager的實現傳遞給bean。然後,通過使用TransactionDefinitionReactiveTransaction對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);

reactiveTx.flatMap(status -> {

    Mono<Object> tx = ...; // put your business logic here

    return tx.then(txManager.commit(status))
            .onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});

Spring框架通過使用以下兩種方式提供編程式事務管理的方法:

  • TransactionTemplateTransactionalOperator
  • TransactionManager直接實現

Spring團隊通常建議對命令式流程中的編程式事務管理推薦使用TransactionTemplate,對響應性代碼推薦TransactionalOperator。第二種方法類似於使用JTA UserTransaction API,儘管異常處理的麻煩程度較小。

1.5.1 使用TransactionTemplate

TransactionTemplate採用與其他Spring模板(如JdbcTemplate)相同的方法。它使用一種回調方法(使應用程序代碼不必進行樣板獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。

如下面的示例所示,使用TransactionTemplate完全將你與Spring的事務基礎結構和api結合在一起。編程式事務管理是否適合你的開發需求是你必須自己做的決定。

必須在事務上下文中運行並且顯式使用TransactionTemplate的應用程序代碼類似於下一個示例。作為應用程序開發人員,你可以編寫TransactionCallback實現(通常表示為匿名內部類),其中包含你需要在事務上下文中運行的代碼。然後,你可以將自定義TransactionCallback的實例傳遞給TransactionTemplate上暴露的execute(..)方法。以下示例顯示瞭如何執行此操作:

public class SimpleService implements Service {

    // single TransactionTemplate shared amongst all methods in this instance
    private final TransactionTemplate transactionTemplate;

    // use constructor-injection to supply the PlatformTransactionManager
    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }

    public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {
            // the code in this method runs in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }
}

如果沒有返回值,則可以將便捷的TransactionCallbackWithoutResult類與匿名類一起使用,如下所示:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        updateOperation1();
        updateOperation2();
    }
});

回調中的代碼可以通過在提供的TransactionStatus對象上調用setRollbackOnly()方法來回滾事務,如下所示:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
            updateOperation1();
            updateOperation2();
        } catch (SomeBusinessException ex) {
            status.setRollbackOnly();
        }
    }
});

指定事物配置

你可以通過編程方式或配置方式在TransactionTemplate上指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionTemplate實例具有默認的事務設置。以下示例顯示了針對特定TransactionTemplate的事務設置的編程自定義:

public class SimpleService implements Service {

    private final TransactionTemplate transactionTemplate;

    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired
        this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        this.transactionTemplate.setTimeout(30); // 30 seconds
        // and so forth...
    }
}

以下示例通過使用Spring XML配置來定義帶有一些自定義事務設置的TransactionTemplate

<bean id="sharedTransactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
    <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
    <property name="timeout" value="30"/>
</bean>

然後,你可以將sharedTransactionTemplate注入到所需的服務中。

最後,TransactionTemplate類的實例是線程安全的,因為這些實例不維護任何對話狀態。但是,TransactionTemplate實例確實會維護配置狀態。因此,儘管許多類可以共享一個TransactionTemplate實例,但是如果一個類需要使用具有不同設置(例如,不同的隔離級別)的TransactionTemplate,則需要創建兩個不同的TransactionTemplate實例。

參考代碼:org.liyong.dataaccess.starter.TransactionTemplateIocContainer

1.5.2 使用TransactionOperator

TransactionOperator遵循類似於其他響應式操作符的設計。它使用一種回調方法(使應用程序代碼不必進行模版獲取和釋放事務性資源),並生成意向驅動的代碼,因為你的代碼僅專注於你要執行的操作。

如以下示例所示,使用TransactionOperator絕對可以使你與Spring的事務基礎結構和API結合。編程式事務管理是否適合你的開發需求是你必須自己做的決定。

必須在事務上下文中運行並且顯式使用TransactionOperator的應用程序代碼類似於下一個示例:

public class SimpleService implements Service {

    // single TransactionOperator shared amongst all methods in this instance
    private final TransactionalOperator transactionalOperator;

    // use constructor-injection to supply the ReactiveTransactionManager
    public SimpleService(ReactiveTransactionManager transactionManager) {
        this.transactionOperator = TransactionalOperator.create(transactionManager);
    }

    public Mono<Object> someServiceMethod() {

        // the code in this method runs in a transactional context

        Mono<Object> update = updateOperation1();

        return update.then(resultOfUpdateOperation2).as(transactionalOperator::transactional);
    }
}

TransactionalOperator可以通過兩種方式使用:

  • 使用Reactor類型的操作符樣式(mono.as(transactionalOperator :: transactional))
  • 其他所有情況的回調樣式(transactionalOperator.execute(TransactionCallback <T>))

回調中的代碼可以通過在提供的ReactiveTransaction對象上調用setRollbackOnly()方法來回滾事務,如下所示:

transactionalOperator.execute(new TransactionCallback<>() {

    public Mono<Object> doInTransaction(ReactiveTransaction status) {
        return updateOperation1().then(updateOperation2)
                    .doOnError(SomeBusinessException.class, e -> status.setRollbackOnly());
        }
    }
});

取消信號

在響應式流中,Subscriber可以取消其Subscription並停止其PublisherProject Reactor以及其他庫中的操作符,例如next()take(long)timeout(Duration)等,都可以發出取消操作。沒有辦法知道取消的原因,無論是由於錯誤還是僅僅是出於進一步消費的興趣,並且在5.2版中,TransactionalOperator默認在取消時提交事務。在版本5.3中,這種行為將發生改變,事務將在取消時回滾,以創建可靠的和確定性的結果。因此,重要的是要考慮從事務發佈服務器下游使用的操作符。特別是在Flux或其他多值Publisher的情況下,必須使用完整的輸出以允許事務完成。

指定事物配置

你可以為TransactionalOperator指定事務設置(例如傳播模式、隔離級別、超時等)。默認情況下,TransactionalOperator實例具有默認的事務設置。以下示例顯示了針對特定TransactionalOperator的事務設置的自定義:

public class SimpleService implements Service {

    private final TransactionalOperator transactionalOperator;

    public SimpleService(ReactiveTransactionManager transactionManager) {
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();

        // the transaction settings can be set here explicitly if so desired
        definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        definition.setTimeout(30); // 30 seconds
        // and so forth...

        this.transactionalOperator = TransactionalOperator.create(transactionManager, definition);
    }
}
1.5.3 使用TransactionManager

以下各節說明命令式和響應式事務管理器的用法。

使用PlatformTransactionManager

對於命令式事務,可以直接使用org.springframework.transaction.PlatformTransactionManager來管理事務。為此,通過bean引用將你使用的PlatformTransactionManager的實現傳遞給bean。然後,通過使用TransactionDefinitionTransactionStatus對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    // put your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

使用ReactiveTransactionManager

使用響應式事務時,可以直接使用org.springframework.transaction.ReactiveTransactionManager來管理事務。為此,請通過bean引用將你使用的ReactiveTransactionManager的實現傳遞給bean。然後,通過使用TransactionDefinitionReactiveTransaction對象,可以啟動事務、回滾和提交。以下示例顯示瞭如何執行此操作:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

Mono<ReactiveTransaction> reactiveTx = txManager.getReactiveTransaction(def);

reactiveTx.flatMap(status -> {

    Mono<Object> tx = ...; // put your business logic here

    return tx.then(txManager.commit(status))
            .onErrorResume(ex -> txManager.rollback(status).then(Mono.error(ex)));
});

作者

個人從事金融行業,就職過易極付、思建科技、某網約車平臺等重慶一流技術團隊,目前就職於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分佈式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公眾號和博客站點對知識體系進行分享。關注公眾號:青年IT男 獲取最新技術文章推送!

博客地址: http://youngitman.tech

CSDN: https://blog.csdn.net/liyong1028826685

微信公眾號:

技術交流群:

Leave a Reply

Your email address will not be published. Required fields are marked *