SpringBoot 系列教程之編程式事務使用姿式介紹篇

SpringBoot 系列教程之編程式事務使用姿式介紹篇java

前面介紹的幾篇事務的博文,主要是利用@Transactional註解的聲明式使用姿式,其好處在於使用簡單,侵入性低,可辨識性高(一看就知道使用了事務);然而缺點也比較明顯,不夠靈活,稍不注意,可能就由於姿式不對,致使事務不生效mysql

本文將介紹另一種事務的使用姿式,藉助TransactionTemplate的編程式事務git

<!-- more -->github

I. 配置

本篇主要介紹的是jdbcTemplate+transactionTemplate來完成一個編程式事務的實例 demospring

建立一個 SpringBoot 項目,版本爲2.2.1.RELEASE,使用 mysql 做爲目標數據庫,存儲引擎選擇Innodb,事務隔離級別爲 RRsql

1. 項目配置

在項目pom.xml文件中,加上spring-boot-starter-jdbc,會注入一個DataSourceTransactionManager的 bean,提供了事務支持數據庫

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

2. 數據庫配置

進入 spring 配置文件application.properties,設置一下 db 相關的信息編程

## DataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=

3. 數據庫

新建一個簡單的表結構,用於測試app

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '錢',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

II. 使用說明

1. 初始化

建立幾條數據,用於事務操做ide

@Service
public class ManualDemo {
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init() {
        String sql = "replace into money (id, name, money) values (220, '初始化', 200)";
        jdbcTemplate.execute(sql);
    }
}

2. 使用 case

爲了演示事務的特性,咱們設計幾個簡單的 sql 操做,並拋出異常,引起回滾,以下

  • 在 doUpdate 方法中,顯示更新 name,輸出更新的結果,而後再更新 money 的值,最後拋出一個異常,但願事務回滾
private boolean doUpdate(int id) throws Exception {
    if (this.updateName(id)) {
        this.query("after updateMoney name", id);
        if (this.updateMoney(id)) {
            return true;
        }
    }

    throw new Exception("參數異常");
}


private boolean updateName(int id) {
    String sql = "update money set `name`='更新' where id=" + id;
    jdbcTemplate.execute(sql);
    return true;
}

public void query(String tag, int id) {
    String sql = "select * from money where id=" + id;
    Map map = jdbcTemplate.queryForMap(sql);
    System.out.println(tag + " >>>> " + map);
}

private boolean updateMoney(int id) {
    String sql = "update money set `money`= `money` + 10 where id=" + id;
    jdbcTemplate.execute(sql);
    return false;
}

上面這一端邏輯,若是看了前面幾篇博文,會比較熟悉,區別在於 doUpdate 方法上面沒有添加@Transactional註解,當下它的調用並不會在事務中執行

接下來咱們看一下編程式事務的核心寫法

public void testTransaction(int id) {
    transactionTemplate.execute(new TransactionCallback<Boolean>() {
        @Override
        public Boolean doInTransaction(TransactionStatus transactionStatus) {
            try {
                return doUpdate(id);
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                return false;
            }
        }
    });
}

如上,將方法的調用,封裝在transactionTemplate.execute的調用中,經過設置transactionStatus.setRollbackOnly()來標記回滾

經過前面幾篇博文的學習咱們知道實際使用時,事務的隔離級別,傳遞屬性也很重要,在編程式事務中,固然也是能夠設置的

// 設置隔離級別
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 設置傳播屬性
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

最後寫一個測試代碼,驗證一下是否生效

@Component
public class TransactionalSample {
    @Autowired
    private ManualDemo manualDemo;

    public void testManualCase() {
        System.out.println("======= 編程式事務 start ========== ");
        manualDemo.query("transaction before", 220);
        manualDemo.testTransaction(220);
        manualDemo.query("transaction end", 220);
        System.out.println("======= 編程式事務 end ========== ");
    }
}

輸出結果以下,最終數據 big 沒有被修改

======= 編程式事務 start ==========
transaction before >>>> {id=220, name=初始化, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
after updateMoney name >>>> {id=220, name=更新, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
transaction end >>>> {id=220, name=初始化, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
======= 編程式事務 end ==========

III. 其餘

0. 系列博文&源碼

系列博文

源碼

1. 一灰灰 Blog

盡信書則不如,以上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激

下面一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛

一灰灰blog

相關文章
相關標籤/搜索