Spring之路(38)–基於PlatformTransactionM

wangsys發表於2021-09-09

程式設計式事務管理

所謂程式設計式事務管理,就是使用普通的程式程式碼來管理事務,像上一篇原生JDBC事務實現就是程式設計式的。

與程式設計式事務相對應的就是宣告式事務管理,透過對方法或類新增註解的方式,宣告該方法或類開啟事務。很明顯宣告式事務程式碼量更少更加簡單,更加高階,平時用的也更多,但是我們還是從最基礎的程式設計式事務開始講起。

具體實現

PlatformTransactionManager是Spring封裝好介面,其使用方法跟原生JDBC幾乎一樣,將其生成bean納入Spring容器管理後呼叫即可。

注意PlatformTransactionManager是介面,具體操作需要呼叫其具體實現類,一般透過資料來源訪問資料庫的可以使用DataSourceTransactionManager。注意還有一些其他的PlatformTransactionManager具體實現類,到目前為止我們都是使用JDBC資料來源訪問資料庫的,所以瞭解DataSourceTransactionManager已足夠。

首先定義配置類:

package org.maoge.plantformtran;

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 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;
   }

   /**
    * 配置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;
   }
}

然後定義資料物件Do及資料操作類Dao

package org.maoge.nameddemo;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.jdbc.core.RowMapper;
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);
   }

   /**
    * 刪除
    */
   public void delete(Long id) {
   	Map<String, Object> map = new HashMap<>();
   	map.put("id", id);
   	namedTemplate.update("delete from blog where id =:id", map);
   }

   /**
    * 更新
    */
   public void update(BlogDo blog) {
   	Map<String, Object> map = new HashMap<>();
   	map.put("author", blog.getAuthor());
   	map.put("content", blog.getContent());
   	map.put("title", blog.getTitle());
   	map.put("id", blog.getId());
   	namedTemplate.update("update blog set author=:author,content=:content,title=:title where id=:id", map);
   }

   /**
    * 按id查詢
    */
   public BlogDo getById(Long id) {
   	Map<String, Object> map = new HashMap<>();
   	map.put("id", id);
   	return namedTemplate.queryForObject("select * from blog where id=:id", map, new RowMapper<BlogDo>() {
   		@Override
   		public BlogDo mapRow(ResultSet rs, int rowNum) throws SQLException {
   			BlogDo blog = new BlogDo();
   			blog.setAuthor(rs.getString("author"));
   			blog.setContent(rs.getString("content"));
   			blog.setId(rs.getLong("id"));
   			blog.setTitle(rs.getString("title"));
   			return blog;
   		}
   	});
   }

   /**
    * 查詢列表
    */
   public List<BlogDo> getList() {
   	return namedTemplate.query("select * from blog", new RowMapper<BlogDo>() {
   		@Override
   		public BlogDo mapRow(ResultSet rs, int rowNum) throws SQLException {
   			BlogDo blog = new BlogDo();
   			blog.setAuthor(rs.getString("author"));
   			blog.setContent(rs.getString("content"));
   			blog.setId(rs.getLong("id"));
   			blog.setTitle(rs.getString("title"));
   			return blog;
   		}
   	});
   }
}
package org.maoge.nameddemo;
/**
* @theme 資料物件--部落格
* @author maoge
* @date 2020-01-27
*/
public class BlogDo {
   private Long id;
   private String title;
   private String author;
   private String content;
   // 省略get get
}

最後編寫測試程式碼:

package org.maoge.plantformtran;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class Main {
	public static void main(String[] args) {
		// 獲取容器
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
		// 容器中獲取事務管理元件
		PlatformTransactionManager transactionManager = (PlatformTransactionManager) context
				.getBean("transactionManager");
		// 開始事務
		TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
		TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
		// 容器中獲取資料庫操作元件
		BlogDao blogDao = (BlogDao) context.getBean("blogDao");
		try {
			// 執行資料庫操作
			BlogDo blog = new BlogDo();
			blog.setContent("測試");
			blogDao.insert(blog);
			// 模擬異常
			int a = 1 / 0;
			blogDao.insert(blog);
			// 提交事務
			transactionManager.commit(status);
		} catch (Exception e) {
			// 發生異常則回滾
			transactionManager.rollback(status);
			e.printStackTrace();
		}
	}
}

由於中間執行int a = 1 / 0;發生異常,導致事務回滾,所以實際上一條記錄都沒插入成功。

總結

使用基於PlatformTransactionManager的程式設計式事務管理,跟原生JDBC相比並未節省什麼程式碼,提供了封裝事務的元件,這種方式基本沒人使用,僅作為了解吧。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3244/viewspace-2824858/,如需轉載,請註明出處,否則將追究法律責任。

相關文章