事务定义接口
事务定义接口TransactionDefinition中定义了事务描述相关的三类常量:事务隔离级别、事务传播行为、事务默认超时时限、以及对它们的操作。
事务隔离级别常量5个(掌握)
ISOLATION_DEFAULT:采用默认的事务隔离级别,Mysql默认为ISOLATION_REPEATABLE_READ,Oracle默认为ISOLATION_READ_COMMITTED
ISOLATION_READ_UNCOMMITTED:读未提交,未解决任何并发问题
ISOLATION_READ_COMMITTED:读已提交,解决脏读,存在不可重复读与幻读
ISOLATION_REPEATABLE_READ:可重复读,解决脏读、存在幻读
ISOLATION_SERIALIZABLE:串行化,不存在并发问题
事务的超时时间:
表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚,
单位秒,整数值,默认-1
事务的传播行为7个:
控制业务是不是有事务的,是什么样的事务,表示你的业务方法调用时,事务在方法之间是如何使用的
PROPAGATION_REQUIRED:指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务,若当前没有事务,则创建一个新事物,这种传播行为是最常见的选择,也是Spring默认的事务传播行为
PROPAGATION_REQUIRES_NEW:总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕
PROPAGATION_SUPPORTS:指定的方法支持当前事务,若当前没有事务,也可以以非事务方式执行
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
使用Spring的事务注解管理事务
通过@Transactional注解方式,可将事务添加到public方法中,实现事务管理
@Transactional的所有可选属性如下
propagation:用于设置事务传播性,该属性类型为propagation枚举,默认值为Propagation.REQUIRED
isolation:用于设置事务的隔离级别,该属性类型为lsolation枚举,默认值为lsolation.DEFAULT
readOnly:用于设置该方法对数据库的操作是否是只读的,该属性为boolean,默认值为false
timeout:用于设置本操作与数据库连接超时时限,单位为秒,类型int,默认值为-1,即没有时限
rollbackFor:指定需要回滚的异常类,类型为Class[],默认值为空数组,当然,若只有一个异常类时,可以不使用数组。
noRollbackFor:指定不需要回滚的异常类,类型为Class[],默认值为空数组
noRollbackForClassName:指定不需要回滚的异常类类名,类型为String[],默认值为空数组
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
//rollbackFor表示发生指定异常一定回滚
rollbackFor = {
NullPointerException.class,NullPointerException.class
}
)
注意,@Transactional若用在方法上,只能用在public方法上,对于其他非public方法,如果加上了注解@Transactional,虽然Spring不会报错,但不会将指定事务添加到该方法中,因为Spring会忽略掉所有非public方法上的@Transactiona注解
使用Spring自带@Transactional注解的步骤:
1.需要声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager"/>
<!--使用spring的事务处理-->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接数据库,指定数据源-->
<property name="dataSource" ref="MyDataSource"/>
</bean>
2.开启事务注解驱动,告诉spring框架,要使用注解的方式管理驱动
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能
spring给业务方法加入事务,在你业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
<!--开启事务注解驱动,告诉spring用注解管理事务,创建代理对象-->
<tx:annotation-driven transaction-manager="TransactionManager"/>
3.在方法上面加入@Transactional
package com.bjpowernode.service.impl;
import com.bjpowernode.dao.GoodsDao;
import com.bjpowernode.dao.SaleDao;
import com.bjpowernode.domian.Goods;
import com.bjpowernode.domian.Sale;
import com.bjpowernode.service.GoodsService;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class GoodsServiceImpl implements GoodsService {
private SaleDao saleDao;
private GoodsDao goodsDao;
public void setSaleDao(SaleDao saleDao) {
this.saleDao = saleDao;
}
public void setGoodsDao(GoodsDao goodsDao) {
this.goodsDao = goodsDao;
}
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
//rollbackFor表示发生指定异常一定回滚
rollbackFor = {
NullPointerException.class,NullPointerException.class
}
)
@Override
public void buy(Integer goodsId, Integer nums) {
//记录销售信息,向sale表添加记录
Sale sale = new Sale();
sale.setGid(goodsId);
sale.setNums(nums);
saleDao.insertSale(sale);
//更新库存
Goods goods = goodsDao.selectGoods(goodsId);
if(goods == null){
throw new NullPointerException("标号是:"+goodsId+",的商品不存在");
}else if (goods.getAmount()<nums){
throw new NullPointerException("编号是:"+goodsId+",库存不足");
}
//修改库存
Goods goods1 = new Goods();
goods1.setId(goodsId);
goods1.setAmount(nums);
goodsDao.updateGoods(goods1);
System.out.println("===buy()方法执行完毕 ===");
}
}
---------------------------------------------------------------
使用aspectJ框架功能,在spring配置文件中声明类,方法需要的事务,这种方式业务方法和事务配置完全分离
实现步骤:
都是在spring配置文件.xml文件中实现
1.要使用aspectJ框架,需要加入依赖
pom中加入aspectj框架依赖
<!--aspectj依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2.声明事务管理器对象
在spring配置文件中添加
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--声明数据源,(数据库连接对象)-->
<property name="dataSource" ref="MyDataSource"/>
</bean>
3.声明方法需要的事务类型(配置方法的事务属性,传播行为,隔离级别,超时)
在spring配置文件中添加
<!--
声明事务属性(隔离级别,传播行为,超时时间)
id:自定义名称
transaction-manager:事务管理器对象的id
<tx:advice>和</tx:advice>之间配置内容的
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes><!--配置事务属性-->
<!--tx:method:给具体的方法配置事务,method可以有多个,给不同的方法配置事务
name:完整的方法名
propagation:传播行为
isolation:隔离级别
rollback-for:指定异常的全限定类名,发生异常一定回滚
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="NullPointerException,NullPointerException"/>
</tx:attributes>
</tx:advice>
4.配置aop:指定哪些类要创建代理
在spring配置文件中添加
<!--配置aop指明哪个类需要添加事务-->
<aop:config>
<!--配置切入表达式,指定哪些包中的类,要使用事务
id:切入点表达式名称,唯一值
expression:切入点表达式
-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!--配置增强器:关联adivce和pointcut
advice-ref:关联,上面<tx:advice>配置的内容
pointcut-ref:切入点表达式id
-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/>
</aop:config>