Spring之路(38)–基于PlatformTransactionManager的编程式事务管理

1. 编程式事务管理

所谓编程式事务管理,就是使用普通的程序代码来管理事务,像上一篇原生JDBC事务实现就是编程式的。


与编程式事务相对应的就是声明式事务管理,通过对方法或类添加注解的方式,声明该方法或类开启事务。很明显声明式事务代码量更少更加简单,更加高级,平时用的也更多,但是我们还是从最基础的编程式事务开始讲起。


2. 具体实现

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;发生异常,导致事务回滚,所以实际上一条记录都没插入成功。


3. 总结

使用基于PlatformTransactionManager的编程式事务管理,跟原生JDBC相比并未节省什么代码,提供了封装事务的组件,这种方式基本没人使用,仅作为了解吧。

上一篇:浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试


下一篇:WCF技术剖析之三十一: WCF事务编程[下篇]