天天看點

Spring之路(39)–基于TransactionTemplate的程式設計式事務管理

1. 背景

上一篇實作的基于PlatformTransactionManater的程式設計式事務管理,是屬于非常低級的封裝,其實就是将原來的JDBC事務操作封裝為一個接口而已,然後由具體的實作類來實作。

本篇通過TransactionTemplate類,實作了對固定流程代碼的封裝,隻需要将視作原子性操作的幾個資料庫操作放入一個方法中處理即可實作事務。

2. 代碼實作

修改配置類,在上一篇注冊PlatformTransactionManater類型bean的基礎上,注冊TransactionTemplate類型的bean,代碼如下:

package org.maoge.templatetran;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import com.alibaba.druid.pool.DruidDataSource;
/**
* Spring配置類
*/
@Configuration
public class SpringConfig {
   /**
    * 定義資料源bean
    */
   @Bean
   public DataSource dataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8");
    dataSource.setUsername("root");
    dataSource.setPassword("Easy@0122");
    return dataSource;
   }
   /**
    * 定義事務管理bean
    */
   @Bean
   public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource());// 注入dataSource
    return transactionManager;
   }
   /**
    * 定義TransactionTemplate類型的bean
    */
   @Bean
   public TransactionTemplate transactionTemplate() {
    TransactionTemplate transactionTemplate=new TransactionTemplate();
    transactionTemplate.setTransactionManager(transactionManager());//注入事務管理器
    return transactionTemplate;
   }
   /**
    * 配置namedParameterJdbcTemplate元件
    */
   @Bean
   public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource());// 注入dataSource
    return template;
   }
   /**
    * 為BlogDao注冊bean
    */
   @Bean
   public BlogDao blogDao() {
    BlogDao blogDao = new BlogDao();
    blogDao.setNamedTemplate(namedParameterJdbcTemplate());// 注入namedParameterJdbcTemplate
    return blogDao;
   }
}
      

資料對象BlogDo和資料操作對象BlogDao沒有任何變化:

package org.maoge.templatetran;
import java.util.HashMap;
import java.util.Map;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
/**
* @theme DAO--部落格
* @author maoge
* @date 2020-01-29
*/
public class BlogDao {
   public NamedParameterJdbcTemplate getNamedTemplate() {
    return namedTemplate;
   }
   public void setNamedTemplate(NamedParameterJdbcTemplate namedTemplate) {
    this.namedTemplate = namedTemplate;
   }
   private NamedParameterJdbcTemplate namedTemplate;
   /**
    * 新增
    */
   public void insert(BlogDo blog) {
    Map<String, Object> map = new HashMap<>();
    map.put("author", blog.getAuthor());
    map.put("content", blog.getContent());
    map.put("title", blog.getTitle());
    // 注意使用:xxx占位
    namedTemplate.update("insert into blog(author,content,title)values(:author,:content,:title)", map);
   }
}
      
package org.maoge.templatetran;
/**
 * @theme 資料對象--部落格
 * @author maoge
 * @date 2020-01-27
 */
public class BlogDo {
    private Long id;
    private String title;
    private String author;
    private String content;
    // 省略get get
}
      
測試驗證,注意使用事務時,通過TransactionTemplate類的方法使用:

package org.maoge.templatetran;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class Main {
    public static void main(String[] args) {
        // 擷取容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 容器中擷取TransactionTemplate
        TransactionTemplate transactionTemplate = (TransactionTemplate) context.getBean("transactionTemplate");
        // 容器中擷取資料庫操作元件
        BlogDao blogDao = (BlogDao) context.getBean("blogDao");
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            // 注意!該方法中的操作會實作事務
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                BlogDo blog = new BlogDo();
                blog.setContent("測試");
                blogDao.insert(blog);
                int a = 1 / 0;// 發生異常,導緻事務復原,是以并不會插入任何一行資料
                blogDao.insert(blog);
            }
        });
    }
}
      

需要注意的是,TransactionTemplate執行時,不論發生受檢查的異常(Exception),還是不受檢查的異常(RuntimeException),均會執行復原操作,這個是比較符合我們期望的,在下一篇聲明式事務管理裡面,你會發現預設情況不是這樣的,有點小坑啊。