Spring 声明式事务
1 何为事务
事务:一批数据,要么同时成功保存到数据库,要么同时提交到数据库失败
Mybatis中需要手动操作进行commit与rollback
Spring 提供了声明式事务处理方法
2 声明事务的配置
2.1 应用上下文开启事务配置
applicationContext.xml 中需要增加如下设置
2.1.1 头部增加
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
2.1.2 增加bean
注意:ref="dataSource"
这里引用的是你自己项目里的数据源,数据源id是什么这里就写什么
<!--事务管理器transactionManager提供了声明式事务的支持,在程序成功提交,抛出"运行时异常"时进行回滚-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启注解形式的声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
3 声明式事务如何使用
3.1 示例
比如说要初始化多条数据,要求插入时必须全部成功,或者全部失败
准备好各个层所用的方法
3.1.1 mapper xml层
<insert id="insert" parameterType="com.zhangyx.ssm.entity.Goods">
INSERT INTO `babytun`.`t_goods`(`title`, `sub_title`, `original_cost`, `current_price`, `discount`, `is_free_delivery`, `category_id`)
VALUES (#{goods.title}, #{goods.subTitle}, #{goods.originalCost}, #{goods.currentPrice}, #{goods.discount}, #{goods.isFreeDelivery}, #{goods.categoryId})
<selectKey resultType="int" keyProperty="goodsId" order="AFTER">
select last_insert_id()
</selectKey>
</insert>
3.1.2 mapper class 层
int insert(Goods goods);
3.1.3 Service层
//初始化十条数据
public void initGoods(){
for (int i =0;i < 10 ;i++){
Goods goods = new Goods();
goods.setCategoryId(i);
goods.setCurrentPrice(10f*2);
goods.setDiscount(10f);
goods.setIsFreeDelivery(i);
goods.setOriginalCost(20f);
goods.setSubTitle("模拟初始化数据");
goods.setTitle("模拟初始化数据");
goodsMapper.insert(goods);
}
}
3.1.4 测试
是写测试还是网页调测试自己选择
如果在i=3的时候,程序报错了,这里模拟程序出现异常,代码加入
if(i==3){
throw new RuntimeException(“RuntimeException”);
}
模拟程序出错
//初始化十条数据
public void initGoods(){
for (int i =0;i < 10 ;i++){
if(i==3){
throw new RuntimeException(“RuntimeException”);
}
Goods goods = new Goods();
goods.setCategoryId(i);
goods.setCurrentPrice(10f*2);
goods.setDiscount(10f);
goods.setIsFreeDelivery(i);
goods.setOriginalCost(20f);
goods.setSubTitle("模拟初始化数据");
goods.setTitle("模拟初始化数据");
goodsMapper.insert(goods);
}
}
页面请求报如下错
我们看一下数据库数据
看到结果,只插入了三条数据,如果这是银行转账,岂不是很危险
所以这个时候就用到了事务,Spring为我们提供了声明式事务,不用再用Mybatis的手动rollback操作
一般声明式事务在service层使用,直接使用在类上或者方法上,在方法上只在此方法内起作用,在类上使用则该类内的方法全部开启事务
3.2 方法上使用
3.3 类上使用
3.4 测试
程序报错,并且自动进行了回滚,数据也没有插入到数据库,测试成功
4 设置不使用事务
如果事务放到了类上,但是我们有类中有查询方法,查询方法是不需要使用事务的,可以使用propagation = Propagation.NOT_SUPPORTED设置不使用事务,并且设置为只读的readOnly=true
5 事务作用域
上面我们使用了throw new RuntimeException()异常模拟了,程序出现异常的情况,如果程序不是出现了这个异常,而是出现了其他的异常呢,例如说抛出了ParseException(“”,1),我们来测试看一下
我们看到虽然异常抛出了,但是也有数据数据也进入了数据库
那么我们可以知道,@Transactionnal只对 运行时异常(RuntimeException)起作用,那么如果出现别的问题应该怎么办呢,此时只需要指定此注解起作用的类@Transactional(rollbackFor = Exception.class)即可
6 指定rollbackFor
指定rollbackFor才是此注解的真正用法