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

简介: 本文目录1. 编程式事务管理2. 具体实现3. 总结

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

相关文章
|
2月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
403 0
|
3月前
|
Java API 开发者
Spring 控制反转与依赖注入:从玄学编程到科学管理
在传统开发中,手动`new`对象导致紧耦合、难以维护和测试。控制反转(IoC)将对象创建交给框架,实现解耦。Spring通过IOC容器自动管理对象生命周期,开发者只需声明依赖,无需关心创建细节。依赖注入(DI)是IoC的具体实现方式,支持构造器、Setter和字段注入。构造器注入推荐使用,保证依赖不可变且易于测试。对于多个同类型Bean,可用`@Qualifier`或`@Primary`解决冲突。此外,Spring还支持依赖查找(DL),开发者主动从容器获取Bean,适用于动态场景,但侵入性强。掌握IoC与DI,有助于构建灵活、可维护的Spring应用。
|
1月前
|
监控 Java 数据库连接
《深入理解Spring》事务管理——数据一致性的守护者
Spring事务管理确保数据一致性,支持声明式与编程式两种方式。通过@Transactional注解简化配置,提供传播行为、隔离级别、回滚规则等灵活控制,结合ACID特性保障业务逻辑可靠执行。
|
1月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
3月前
|
人工智能 监控 安全
Spring AOP切面编程颠覆传统!3大核心注解+5种通知类型,让业务代码纯净如初
本文介绍了AOP(面向切面编程)的基本概念、优势及其在Spring Boot中的使用。AOP作为OOP的补充,通过将横切关注点(如日志、安全、事务等)与业务逻辑分离,实现代码解耦,提升模块化程度、可维护性和灵活性。文章详细讲解了Spring AOP的核心概念,包括切面、切点、通知等,并提供了在Spring Boot中实现AOP的具体步骤和代码示例。此外,还列举了AOP在日志记录、性能监控、事务管理和安全控制等场景中的实际应用。通过本文,开发者可以快速掌握AOP编程思想及其实践技巧。
|
7月前
|
Java 关系型数据库 MySQL
深入解析 @Transactional——Spring 事务管理的核心
本文深入解析了 Spring Boot 中 `@Transactional` 的工作机制、常见陷阱及最佳实践。作为事务管理的核心注解,`@Transactional` 确保数据库操作的原子性,避免数据不一致问题。文章通过示例讲解了其基本用法、默认回滚规则(仅未捕获的运行时异常触发回滚)、因 `try-catch` 或方法访问修饰符不当导致失效的情况,以及数据库引擎对事务的支持要求。最后总结了使用 `@Transactional` 的五大最佳实践,帮助开发者规避常见问题,提升项目稳定性与可靠性。
1182 12
|
10月前
|
人工智能 Java API
阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手
本次分享的主题是阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手,由阿里云两位工程师分享。
507 2
阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手
|
10月前
|
XML 监控 前端开发
Spring Boot中的WebFlux编程模型
Spring WebFlux 是 Spring Framework 5 引入的响应式编程模型,基于 Reactor 框架,支持非阻塞异步编程,适用于高并发和 I/O 密集型应用。本文介绍 WebFlux 的原理、优势及在 Spring Boot 中的应用,包括添加依赖、编写响应式控制器和服务层实现。WebFlux 提供高性能、快速响应和资源节省等优点,适合现代 Web 应用开发。
1179 15
|
11月前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
162 2
一键注入 Spring 成员变量,顺序编程