5. Spring的事务管理

5.1 事务管理概述

在负责事务管理的jar包中,找到trancation包,其中包括事务管理的三个核心接口:PlatformTransactionManager、TransactionDefinition 和 TransactionStatus。

5.1.1事务管理的核心接口

1.PlatformTrancationManager
这个接口是Spring提供的平台事务管理器,主要用于管理事务,包含三个用于事务操作的方法。

  • TransactionStatus getTransaction(TransactionDefinition
    definition):用于获取事务状态信息。
  • void commit(TransactionStatus status):用于提交事务。
  • void rollback(TransactionStatus status):用于回滚事务。

2.TransactionDefinition
TransactionDefinition 接口是事务定义(描述)的对象,它提供了事务相关信息获取的方法,其中包括五个操作,具体如下。

  • String getName():获取事务对象名称。
  • int getIsolationLevel():获取事务的隔离级别。
  • intgetPropagationBehavior():获取事务的传播行为。
  • int getTimeout():获取事务的超时时间。
  • boolean isReadOnly():获取事务是否只读。
    传播行为的种类如下表所示:
属性名称 描述
PROPAGATION_REQUIRED required 支持当前事务。如果 A 方法已经在事务中,则 B 事务将直接使用。否则将创建新事务
PROPAGATION_SUPPORTS supports 支持当前事务。如果 A 方法已经在事务中,则 B 事务将直接使用。否则将以非事务状态执行
PROPAGATION_MANDATORY mandatory 支持当前事务。如果 A 方法没有事务,则抛出异常
PROPAGATION_REQUIRES_NEW requires_new 将创建新的事务,如果 A 方法已经在事务中,则将 A 事务挂起
PROPAGATION_NOT_SUPPORTED not_supported 不支持当前事务,如果 A 方法在事务中,则抛出异常
PROPAGATION_NEVER never 不支持当前事务,总是以非事务状态执行。如果 A 方法已经在事务中,则将其挂起
PROPAGATION.NESTED nested 嵌套事务,底层将使用 Savepoint 形成嵌套事务

3.TransactionStatus
TransactionStatus 接口是事务的状态,它描述了某一时间点上事务的状态信息。

  1. void flush() 刷新事务
  2. boolean hasSavepoint() 获取是否存在保存点
  3. boolean isCompleted() 获取事务是否完成
  4. boolean isNewTransaction() 获取是否是新事务
  5. boolean isRollbackOnly() 获取是否回滚
  6. void setRollbackOnly() 设置事务回滚

5.1.2事务管理的方式

Spring 事务管理分为两种方式,一种是传统的编程式事务管理,另一种是声明式事务管理。
编程式事务管理:要包括定义事务的开始,正常执行后的事务提交,异常时事务的回滚
声明式事务管理:通过AOP技术实现事务管理

5.2 声明式事务管理

5.2.1 基于xml方式的声明式事务管理

这种方式通过在事务文件中配置事务规则的相关声明来实现,利用tx命名空间来配置事务。该属性配置的结构如下

首先在上次用来声明方法的接口中,声明方法,并在实现类中实现

	public void transfer(String outUser, String inUser, Double money) {
		// TODO Auto-generated method stub
		this.jdbcTemplate.update("update account set balance = balance + ? "
				+"where username = ? ",money,inUser);
//		int i = 1 /0;
		this.jdbcTemplate.update("update account set balance = balance - ? "
				+"where username = ? ",money,outUser);
	}

编写xml文档

	   <!-- 4.事务管理器,依赖于数据源 -->
   <bean id="transactionManager" class=
   "org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
   </bean>	
   <!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
   <tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- name:*表示任意方法名称 -->
			<tx:method name="*" propagation="REQUIRED" 
                           isolation="DEFAULT" read-only="false" />
		</tx:attributes>
	</tx:advice>
	<!-- 6.编写aop,让spring自动对目标生成代理,需要使用AspectJ的表达式 -->
	<aop:config>
		<!-- 切入点 -->
		<aop:pointcut expression="execution(* com.itheima.jdbc.*.*(..))"
			id="txPointCut" />
		<!-- 切面:将切入点与通知整合 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
	</aop:config>

编写测试类,测试运行

	@Test
	public void transtest(){
		  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	      AccountDao accountDao = (AccountDao)applicationContext.getBean("accountDao");
	      accountDao.transfer("张伟隆", "123", 50.0);
	      System.out.print("成功");
	}

运行结果如下

注意这里需要导入新的jar包,起初没注意到这点,在这里改了半天

5.2.2 基于Annotation方式的声明式事务管理

这种方式比较简易,仅仅需要在xml文档中,注册事务注解驱动
将原先xml文档中

	   <!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
	   <tx:advice id="txAdvice" transaction-manager="transactionManager">
			<tx:attributes>
				<!-- name:*表示任意方法名称 -->
				<tx:method name="*" propagation="REQUIRED" 
	                           isolation="DEFAULT" read-only="false" />
			</tx:attributes>
		</tx:advice>
		<!-- 6.编写aop,让spring自动对目标生成代理,需要使用AspectJ的表达式 -->
		<aop:config>
			<!-- 切入点 -->
			<aop:pointcut expression="execution(* com.itheima.jdbc.*.*(..))"
				id="txPointCut" />
			<!-- 切面:将切入点与通知整合 -->
			<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
		</aop:config>

替换为

		<tx:annotation-driven transaction-manager="transactionManager"/>

现在需要在测试方法的上面添加注解

	@Transactional(propagation = Propagation.REQUIRED,
					isolation = Isolation.DEFAULT,readOnly = false)

关于 @Transactional 的参数,有如下

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")

指定多个异常类名称:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时
测试运行成功

posted @ 2021-02-02 13:05  我就是隔壁老张  阅读(132)  评论(0编辑  收藏  举报