在 Spring 中数据库事务是通过 PlatformTransactionManager 进行管理的, jdbcTemplate 是不能支持事务的, 而能够支持事务的是 org.springframework.transaction.support.TransactionTemplate 模板, 它是 Spring 所提供的事务管理器的模板
• 事务的创建, 提交和回滚是通过 PlatformTransactionManager 接口来完成的.
• 当事务产生异常时会回滚事务, 在默认的实现中所有的异常都会回滚. 我们可以通过配置去修改在某些异常发生时回滚或者不回滚事务.
• 当无异常时, 会提交事务.
支持 JTA 事务, 常用的是 DataSourceTransactionManager, 它继承抽象事务管理器 AbstractPlatformTransactionManager, 而 AbstractPlatformTransactionManager 又实现了 PlatformTransactionManager. 这样 Spring 就可以如同源码中看到的那样使用 PlatformTransactionManager 接口的方法, 创建, 提交或者回滚事务了.
配置事务管理器
MyBatis 框架用得最多的事务管理器是 DataSourceTransactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager), 因此下面将以此例进行讲解. 如果使用的持久框架是 Hibernate, 那么你就要用到 spring-ORM 包 org.springframework.ORM.hibernate4.HibernateTransactionManager 了. 它们大同小异, 一般而言我们在使用时, 还会加入 xml 的事务命名空间. 下面配置一个事务管理器
- <?xml version='1.0' encoding='UTF-8' ?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
- <!-- 数据库连接池 -->
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://localhost:3306/springmvc?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true"/>
- <property name="username" value="root"/>
- <property name="password" value="123456"/>
- <property name="maxActive" value="255"/>
- <property name="maxIdle" value="5"/>
- <property name="maxWait" value="10000"/>
- </bean>
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 配置数据源事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- </beans>
这里先引入了 xml 的命名空间, 然后定义了数据库连接池, 于是使用了 DataSourceTransactionManager 去定义数据库事务管理器, 并且注入了数据库连接池. 这样 Spring 就知道你已经将数据库事务委托给事务管理器 transactionManager 管理了. 在 jdbcTemplate 源码分析时, 笔者就已经指出, 数据库资源的产生和释放如果没有委托给数据库管理器, 那么就由 jdbcTemplate 管理, 但是此时已经委托给了事务管理器, 所以 jdbcTemplate 的数据库资源和事务已经由事务管理器处理了.
在 Spring 中可以使用声明式事务或者编程式事务, 如今编程式事务几乎不用了, 因为它会产生冗余, 代码可读性较差. 声明式事务又可以分为 xml 配置和注解事务, 但 xml 方式也已经不常用了, 目前主流方法是注解 @Transactional.
用 Java 配置方式实现 Spring 数据库事务
用 Java 配置的方式来实现 Spring 数据库事务, 需要在配置类中实现接口 TransactionManagementConfigurer 的 annota-tionDrivenTransactionManager 方法. Spring 会把 annotationDrivenTransactionManager 方法返回的事务管理器作为程序中的事务管理器
代码清单: 使用 Java 配置方式实现 Spring 数据库事物
- package com.ssm.chapter13.config;
- import org.apache.commons.dbcp.BasicDataSourceFactory;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.ComponentScan;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.datasource.DataSourceTransactionManager;
- import org.springframework.transaction.PlatformTransactionManager;
- import org.springframework.transaction.annotation.EnableTransactionManagement;
- import org.springframework.transaction.annotation.TransactionManagementConfigurer;
- import javax.sql.DataSource;
- import java.util.Properties;
- @Configuration
- @ComponentScan("com.ssm.chapter13.*")
- // 使用事务驱动管理器
- @EnableTransactionManagement
- public class JavaConfig implements TransactionManagementConfigurer {
- // 数据源
- private DataSource dataSource = null;
- /**
- * 配置数据源. * @return 数据源.
- */
- @Bean(name = "dataSource")
- public DataSource initDataSource() {
- if (dataSource != null) {
- return dataSource;
- }
- Properties props = new Properties();
- props.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver");
- props.setProperty("url", "jdbc:mysql://localhost:3306/springmvc?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true");
- props.setProperty("username", "root");
- props.setProperty("password", "123456");
- props.setProperty("maxActive", "200");
- props.setProperty("maxIdle", "20");
- props.setProperty("maxWait", "30000");
- try {
- dataSource = BasicDataSourceFactory.createDataSource(props);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return dataSource;
- }
- /**
- * 配置 jdbcTemplate * @return jdbcTemplate
- */
- @Bean(name = "jdbcTemplate")
- public JdbcTemplate initjdbcTemplate() {
- JdbcTemplate jdbcTemplate = new JdbcTemplate();
- jdbcTemplate.setDataSource(initDataSource());
- return jdbcTemplate;
- }
- /**
- * 实现接口方法, 使得返回数据库事务管理器
- */
- @Override
- @Bean(name = "transactionManager")
- public PlatformTransactionManager annotationDrivenTransactionManager() {
- DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
- // 设置事务管理器管理的数据源
- transactionManager.setDataSource(initDataSource());
- return transactionManager;
- }
- }
实现了 TransactionManagementConfigurer 接口所定义的方法 annotation DrivenTransactionManager, 并且我们使用 DataSourceTransactionManager 去定义数据库事务管理器的实例, 然后把数据源设置给它. 注意, 使用注解 @EnableTransactionManagement 后, 在 Spring 上下文中使用事务注解 @Transactional,Spring 就会知道使用这个数据库事务管理器管理事务了.
编程式事务
编程式事务以代码的方式管理事务, 换句话说, 事务将由开发者通过自己的代码来实现, 这里需要使用一个事务定义类接口 --TransactionDefinition, 暂时不进行深入的介绍, 我们只要使用默认的实现类 --DefaultTransactionDefinition 就可以了.
代码清单: 编程式事务
- package com.ssm.chapter13.main;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.transaction.PlatformTransactionManager;
- import org.springframework.transaction.TransactionDefinition;
- import org.springframework.transaction.TransactionStatus;
- import org.springframework.transaction.support.DefaultTransactionDefinition;
- public class MainTest {
- public static void main(String[] args) {
- ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter13/spring-cfg.xml");//ctx 为 Spring IoC 容器
- JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
- // 事务定义类
- TransactionDefinition def = new DefaultTransactionDefinition();
- PlatformTransactionManager transactionManager = ctx.getBean(PlatformTransactionManager.class);
- TransactionStatus status = transactionManager.getTransaction(def);
- try {
- // 执行 SQL 语句
- jdbcTemplate.update("insert into t_role(role_name, note)" + "values('role_name_transactionManager','note_transactionManager')");
- // 提交事务
- transactionManager.commit(status);
- } catch (Exception ex) {
- // 回滚事务
- transactionManager.rollback(status);
- }
- }
- }
从代码中可以看到所有的事务都是由开发者自己进行控制的, 由于事务已交由事务管理器管理, 所以 jdbcTemplate 本身的数据库资源已经由事务管理器管理, 因此当它执行完 insert 语句时不会自动提交事务, 这个时候需要使用事务管理器的 commit 方法, 回滚事务需要使用 rollback 方法.
当然这是最简单的使用方式, 因为这个方式已经不是主流方式, 甚至几乎是不被推荐使用的方式, 之所以介绍是因为它的代码流程更为清晰, 有助于未来对编程式事务的理解.
编程式事务是一种约定型的事务, 在大部分情况下, 当使用数据库事务时, 大部分的场景是在代码中发生了异常时, 需要回滚事务, 而不发生异常时则是提交事务, 从而保证数据库数据的一致性.
来源: http://www.bubuko.com/infodetail-3093793.html