Spring学习笔记8——实现事务

这篇博客通过一个电商购买场景,演示了Spring如何利用注解实现事务管理。当操作异常时,事务能够确保数据库状态不受影响,保持数据一致性。文章详细介绍了配置事务管理器、开启事务注解驱动以及在方法上添加事务注解的步骤,并展示了事务生效后的调试结果。
摘要由CSDN通过智能技术生成

用实例来演示spring事务

我们模拟电商形式来验证和实践spring的事务功能

数据库准备
sale表

sale表

goods表

goods表

idea环境准备(略)

环境和前面的笔记内容一直

java代码准备
1、实体类根据数据库来创建(略)
2、dao包

GoodsDao

public interface GoodsDao {
    //更新库存

    int updateGoods(Goods goods);//goods表示本次用户购买的商品信息:id、购买数量

    Goods selectGoods(Integer id);//查询商品信息
}

GoodsDao的mapper文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.trans.dao.GoodsDao">


    <select id="selectGoods" resultType="com.trans.domain.Goods">
        select * from goods where id=#{gid}

    </select>

    <update id="updateGoods">
        update goods set amount = amount - #{amount} where id=#{id}
    </update>

</mapper>

SaleDao

public interface SaleDao {

    int insertSale(Sale sale);//增加销售记录
}  

SaleDao的mapper文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.trans.dao.SaleDao">


    <insert id="insertSale">
        insert into sale(gid,nums) values(#{gid},#{nums});
    </insert>

</mapper>
3、service包

BuyGoodsService

public interface BuyGoodsService {


    void buy(Integer goodsId,Integer nums);//购买商品
}

BuyGoodsServiceImpl

public class BuyGoodsServiceImpl implements BuyGoodsService {

    private SaleDao saleDao;
    private GoodsDao goodsDao;

    public void buy(Integer goodsId, Integer 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方法结束=========");
    }

    public void setSaleDao(SaleDao saleDao) {
        this.saleDao = saleDao;
    }

    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }
}
4、excep包

我们创建一个异常类,继承运行时异常

public class NotEnoughException extends RuntimeException {//自定义运行时异常
    public NotEnoughException() {
        super();
    }

    public NotEnoughException(String message) {
        super(message);
    }
}
5、测试类
public class MyTest {

    @Test
    public void test01(){
        String con="applicationContext.xml";
        ApplicationContext ctx= new ClassPathXmlApplicationContext(con);
        BuyGoodsService bb= (BuyGoodsService) ctx.getBean("buyservice");
        bb.buy(1001,1);
    }
}
调试

当我们的商品id和购买数量都符合程序要求时,可以正常执行购买操作(结果图就不放了);当id或购买量有错误时,程序会返回事先写好的异常语句,且虽然goods表没有进行改动,但是我们可以看到sale表是有记录的(goods表只有两个商品,1001和1002;并且数量都只有几十个,当我们传入的id和nums超出范围,虽然goods表没有改动,但是sale表却记录下来了)

sale表

如果我们想当出现错误异常时,不但不修改goods表,我们也不想在sale表看到记录,这时候就要用到事务了

使用spring事务的步骤
方法一:注解(适合中小项目使用)

spring框架自己用aop实现给业务方法增加事务的功能,使用@Transactional注解(spring框架自己的注解)增加事务;放在public方法的上面,表示当前方法具有事务,可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

1. spring配置文件中声明事务管理器对象
```
<!--spring声明事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--告知连接的数据库(数据源)-->
    <property name="dataSource" ref="myDataSource"/>
</bean>
```
2. 在spring中开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务

spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能;spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知,例如:

    @Around("你要增加的事务功能的业务方法名称")
	Object myAround(){
       开启事务,spring给你开启
		  try{
		     buy(1001,10);
			  spring的事务管理器.commit();
		  }catch(Exception e){
         spring的事务管理器.rollback();
		  }
		 
	 }
下面是具体实现

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

3. 在目标方法的上面加入@Trancational

我们在BuyGoodsServiceImpl类的buy()方法上加上@Trancational

@Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {
                    NullPointerException.class,NotEnoughException.class
            }
    )
  • propagation:用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为
    Propagation.REQUIRED
  • isolation:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为
    Isolation.DEFAULT
  • readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值
    false
  • rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组

一般我们用select查询时,readOnly才设置为truerollbackFor表示发生指定异常一定回滚,spring执行时,先判断抛出的异常是否被包含在rollbackFor中,是则一定回滚,无论什么类型的异常;如果抛出的异常不在rollbackFor中,则spring会判断是否为RuntimeException,是则一定回滚

上面我们用到的都是默认值,所以可以直接写@Transactional
添加事务后调试

我们先正常运行,操作前↓
操作前goods
操作前sale

@Test
    public void test01(){
        String con="applicationContext.xml";
        ApplicationContext ctx= new ClassPathXmlApplicationContext(con);
        BuyGoodsService bb= (BuyGoodsService) ctx.getBean("buyservice");
        bb.buy(1002,10);
    }
正常操作后

正常操作后goods
正常操作后sale
我们试着传入错误参数(错误id或错误nums)

@Test
    public void test01(){
        String con="applicationContext.xml";
        ApplicationContext ctx= new ClassPathXmlApplicationContext(con);
        BuyGoodsService bb= (BuyGoodsService) ctx.getBean("buyservice");
        bb.buy(1004,10);
    }
执行后

抛出异常

异常时sale表

sale表无变化,成功

条条:该学习笔记是记录了我的学习过程,学习自动力节点c语言中文网,有不对的地方欢迎指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值