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相比并未节省什么代码,提供了封装事务的组件,这种方式基本没人使用,仅作为了解吧。