9.3 编程式事务
9.3.1 编程式事务概述
所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。
Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是采用相同的API进行编程。
java代码:Java代码
- Connection conn = null;
- UserTransaction tx = null;
- try {
- tx = getUserTransaction(); //1.获取事务
- tx.begin(); //2.开启JTA事务
- conn = getDataSource().getConnection(); //3.获取JDBC
- //4.声明SQL
- String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";
- PreparedStatement pstmt = conn.prepareStatement(sql);//5.预编译SQL
- ResultSet rs = pstmt.executeQuery(); //6.执行SQL
- process(rs); //7.处理结果集
- closeResultSet(rs); //8.释放结果集
- tx.commit(); //7.提交事务
- } catch (Exception e) {
- tx.rollback(); //8.回滚事务
- throw e;
- } finally {
- conn.close(); //关闭连接
- }
此处可以看到使用UserTransaction而不是Connection连接进行控制事务,从而对于JDBC事务和JTA事务是采用不同API进行编程控制的,并且JTA和JDBC事务管理的异常也是不一样的。
具体如何使用JTA编程进行事务管理请参考cn.javass.spring.chapter9包下的TranditionalTransactionTest类。
而在Spring中将采用一致的事务抽象进行控制和一致的异常控制,即面向PlatformTransactionManager接口编程来控制事务。
9.3.1 Spring对编程式事务的支持
Spring中的事务分为物理事务和逻辑事务;
- 物理事务:就是底层数据库提供的事务支持,如JDBC或JTA提供的事务;
- 逻辑事务:是Spring管理的事务,不同于物理事务,逻辑事务提供更丰富的控制,而且如果想得到Spring事务管理的好处,必须使用逻辑事务,因此在Spring中如果没特别强调一般就是逻辑事务;
逻辑事务即支持非常低级别的控制,也有高级别解决方案:
- 低级别解决方案:
工具类:使用工具类获取连接(会话)和释放连接(会话),如使用org.springframework.jdbc.datasource包中的 DataSourceUtils 类来获取和释放具有逻辑事务功能的连接。当然对集成第三方ORM框架也提供了类似的工具类,如对Hibernate提供了SessionFactoryUtils工具类,JPA的EntityManagerFactoryUtils等,其他工具类都是使用类似***Utils命名;
java代码:Java代码
- //获取具有Spring事务(逻辑事务)管理功能的连接
- DataSourceUtils. getConnection(DataSource dataSource)
- //释放具有Spring事务(逻辑事务)管理功能的连接
- DataSourceUtils. releaseConnection(Connection con, DataSource dataSource)
TransactionAwareDataSourceProxy:使用该数据源代理类包装需要Spring事务管理支持的数据源,该包装类必须位于最外层,主要用于遗留项目中可能直接使用数据源获取连接和释放连接支持或希望在Spring中进行混合使用各种持久化框架时使用,其内部实际使用 DataSourceUtils 工具类获取和释放真正连接;
java代码:Java代码
- <!--使用该方式包装数据源,必须在最外层,targetDataSource 知道目标数据源-->
- <bean id="dataSourceProxy"
- class="org.springframework.jdbc.datasource.
- TransactionAwareDataSourceProxy">
- <property name="targetDataSource" ref="dataSource"/>
- </bean>
通过如上方式包装数据源后,可以在项目中使用物理事务编码的方式来获得逻辑事务的支持,即支持直接从DataSource获取连接和释放连接,且这些连接自动支持Spring逻辑事务;
- 高级别解决方案:
模板类:使用Spring提供的模板类,如JdbcTemplate、HibernateTemplate和JpaTemplate模板类等,而这些模板类内部其实是使用了低级别解决方案中的工具类来管理连接或会话;
Spring提供两种编程式事务支持:直接使用PlatformTransactionManager实现和使用TransactionTemplate模板类,用于支持逻辑事务管理。
如果采用编程式事务推荐使用TransactionTemplate模板类和高级别解决方案。
9.3.3 使用PlatformTransactionManager
首先让我们看下如何使用PlatformTransactionManager实现来进行事务管理:
1、数据源定义,此处使用第7章的配置文件,即“chapter7/ applicationContext-resources.xml”文件。
2、事务管理器定义(chapter9/applicationContext-jdbc.xml):
java代码:Java代码
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
3、 准备测试环境:
3.1、首先准备测试时使用的SQL:
java代码:Java代码
- package cn.javass.spring.chapter9;
- //省略import
- public class TransactionTest {
- //id自增主键从0开始
- private static final String CREATE_TABLE_SQL = "create table test" +
- "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +
- "name varchar(100))";
- private static final String DROP_TABLE_SQL = "drop table test";
- private static final String INSERT_SQL = "insert into test(name) values(?)";
- private static final String COUNT_SQL = "select count(*) from test";
- ……
- }
3.2、初始化Spring容器
java代码:Java代码
- package cn.javass.spring.chapter9;
- //省略import
- public class TransactionTest {
- private static ApplicationContext ctx;
- private static PlatformTransactionManager txManager;
- private static DataSource dataSource;
- private static JdbcTemplate jdbcTemplate;
- ……
- @BeforeClass
- public static void setUpClass() {
- String[] configLocations = new String[] {
- "classpath:chapter7/applicationContext-resources.xml",
- "classpath:chapter9/applicationContext-jdbc.xml"};
- ctx = new ClassPathXmlApplicationContext(configLocations);
- txManager = ctx.getBean(PlatformTransactionManager.class);
- dataSource = ctx.getBean(DataSource.class);
- jdbcTemplate = new JdbcTemplate(dataSource);
- }
- ……
- }
3.3、使用高级别方案JdbcTemplate来进行事务管理器测试:
java代码:Java代码
- @Test
- public void testPlatformTransactionManager() {
- DefaultTransactionDefinition def = new DefaultTransactionDefinition();
- def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
- def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
- TransactionStatus status = txManager.getTransaction(def);
- jdbcTemplate.execute(CREATE_TABLE_SQL);
- try {
- jdbcTemplate.update(INSERT_SQL, "test");
- txManager.commit(status);
- } catch (RuntimeException e) {
- txManager.rollback(status);
- }
- jdbcTemplate.execute(DROP_TABLE_SQL);
- }
- DefaultTransactionDefinition:事务定义,定义如隔离级别、传播行为等,即在本示例中隔离级别为ISOLATION_READ_COMMITTED(提交读),传播行为为PROPAGATION_REQUIRED(必须有事务支持,即如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到这个事务中)。
- TransactionStatus:事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务;
- JdbcTemplate:通过JdbcTemplate对象执行相应的SQL操作,且自动享受到事务支持,注意事务是线程绑定的,因此事务管理器可以运行在多线程环境;
- txManager.commit(status):提交status对象绑定的事务;
- txManager.rollback(status):当遇到异常时回滚status对象绑定的事务。
3.4、使用低级别解决方案来进行事务管理器测试:
java代码:Java代码
- @Test
- public void testPlatformTransactionManagerForLowLevel1() {
- DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
- TransactionStatus status = txManager.getTransaction(def);
- Connection conn = DataSourceUtils.getConnection(dataSource);
- try {
- conn.prepareStatement(CREATE_TABLE_SQL).execute();
- PreparedStatement pstmt = conn.prepareStatement(INSERT_SQL);
- pstmt.setString(1, "test");
- pstmt.execute();
- conn.prepareStatement(DROP_TABLE_SQL).execute();
- txManager.commit(status);
- } catch (Exception e) {
- status.setRollbackOnly();
- txManager.rollback(status);
- } finally {
- DataSourceUtils.releaseConnection(conn, dataSource);
- }
- }
低级别方案中使用DataSourceUtils获取和释放连接,使用txManager开管理事务,而且面向JDBC编程,比起模板类方式来繁琐和复杂的多,因此不推荐使用该方式。在此就不介绍数据源代理类使用了,需要请参考platformTransactionManagerForLowLevelTest2测试方法。
到此事务管理是不是还很繁琐?必须手工提交或回滚事务,有没有更好的解决方案呢?Spring提供了TransactionTemplate模板类来简化事务管理。
9.3.4 使用TransactionTemplate
TransactionTemplate模板类用于简化事务管理,事务管理由模板类定义,而具体操作需要通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为Tra