title: spring事务处理
tag: JAVA
1.几个问题 2.Spring事务处理
文章目录
1.几个问题
1. 什么是事务?
数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列
,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
2. 什么时候要用到事务?
当一个操作涉及多个表或者多条查询语句时,比如转账。java代码中,service类的业务方法中用到多个dao方法,执行多个sql语句,所以开发中service类业务方法上要用到事务
3. 通常使用jdbc和mybatis访问数据库怎么处理事务?
- jdbc处理事务:conn.commit(),conn.rollback
- mybatis处理事务:SqlSession.commit,SqlSession.rollback
4. 3中事务的处理方式有什么不足?
- 不同的数据库访问技术处理事务的对象、方法不同,程序员需要了解各种数据库访问技术处理事务的原理
- 程序员需要掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回滚事务
5. 怎么解决不足?
Spring提供了一种处理事务的统一模型,我们只需要告诉Spring我们用的事mybatis还是hibernate还是其他的数据库访问技术? Spring来进行commit和rollback,我们只需要掌握Spring怎么用就行了。Spring为程序员提供的机制是声明式事务:程序员只需要把事务相关的资源和内容提供给Spring,Spring就知道怎么提交怎么回滚了,我们几乎不用写代码
6. 使用Spring处理事务,我们需要做什么怎么做?
- 前面说声我们只需要把事务相关的资源和内容告诉spring即可,那么什么是事务相关的资源和内容呢?
1. 事务管理器对象,负责事务提交和回滚。
它是一个接口PlatformTransactionManager,不同的数据库访问技术对应不同的实现类,mybatis对应的实现类是DataSourceTransactionManager。所以只需在spring配置文件中使用bean标签声明即可。
2. 业务方法所需事务的属性。
包括:事务的隔离级别、事务的超时时间、事务的传播行为
2.Spring事务处理
1. 使用Spring的@Transactional注解管理事务
适合中小项目,在service实现类的业务方法上加上@Transactional注解,表示该方法是一个事务,注解的属性表示事务的属性
步骤一:配置事务管理器对象
<!--使用spring的事务处理-->
<!--1.声明事务处理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接的数据库-->
<property name="dataSource" ref="dataSource"/>
</bean>
步骤二:开启事务注解驱动
<!--2.开启事务注解驱动,告诉spring使用注解管理事务,创建service代理对象-->
<tx:annotation-driven transaction-manager="transactionManager"/>
步骤三:在方法上加上注解
package xyz.guawaz.service.impl;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import xyz.guawaz.dao.GoodsDao;
import xyz.guawaz.dao.SaleDao;
import xyz.guawaz.domain.Goods;
import xyz.guawaz.domain.Sale;
import xyz.guawaz.exception.NotEnoughException;
import xyz.guawaz.service.BuyGoodsService;
public class BuyGoodsServiceImpl implements BuyGoodsService {
private GoodsDao goodsDao;
private SaleDao saleDao;
public void setGoodsDao(GoodsDao goodsDao) {
this.goodsDao = goodsDao;
}
public void setSaleDao(SaleDao saleDao) {
this.saleDao = saleDao;
}
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
rollbackFor = {
NullPointerException.class,NotEnoughException.class
}
)
@Override
public void buy(int goodsId, int nums) {
System.out.println("==========buy方法的开始==========");
//记录销售信息,向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 NotEnoughException("编号是"+goodsId+"的商品库存不足");
}
//修改库存
Goods buyGoods = new Goods();
buyGoods.setId(goodsId);
buyGoods.setAmount(nums);
goodsDao.updateGoods(buyGoods);
System.out.println("==========buy方法的结束==========");
}
}
2. 使用AspectJ的AOP配置管理事务
适合大型项目,有很多类和方法需要大量的配置事务,使用AapectJ框架的功能,在Spring配置文件中声明类、方法需要的事务,这种方式业务方法和事务配置完全分离
步骤一:引入AspectJ依赖
<!--aspectj依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.9</version>
</dependency>
步骤二:配置事务管理器对象
<!--使用spring的事务处理-->
<!--1.声明事务处理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接的数据库-->
<property name="dataSource" ref="dataSource"/>
</bean>
步骤三: 用tx:advice标签配置业务方法的事务及其属性
隔离级别、传播行为、超时时间
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes><!--配置事务属性-->
<!--name;方法名称,可以写
1.完整的方法名称,不带包和类
2.通配符,*代表任意字符
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.NullPointerException,xyz.guawaz.exception.NotEnoughException"/><!--给具体的方法配置事务属性,method可以有多个-->
<tx:method name="add*" propagation="REQUIRES_NEW"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
步骤四:用aop:config标签配置AOP,指定哪些类要使用事务为其创建代理对象
配置切入点表达式和增强器
<aop:config>
<!--配置切入点表达式,指定哪些包中类要使用事务
id:切入点表达式的名称
expression:切入点表达式,指定哪些类要配置事务,aspectj会创建代理对象
-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!--配置增强器,关联advice和pointcut-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/>
</aop:config>