栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

八、Spring事务(注解方案)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

八、Spring事务(注解方案)

八、Spring事务(注解方案) 1、Spring事务处理模型

*使用步骤是固定的,只要把事务的使用信息提供给Spring就完事了。

  1. 事务内部提交、回滚事务,使用事务管理器对象,代替你完成commit、rolback
    1. 事务管理器是一个接口和它众多的实现类
    2. 事务管理器接口:PlatformTransactionManager,定义了事务重要的方法commit、rolback
    3. 事务管理器接口实现类:Spring把每一种数据库访问技术对应的事务处理类都创建好了
      1. mybatis访问数据库:DataSourceTransactionManager
      2. hibernate访问数据库:HibernateTransactionManager
      3. … …
    4. 使用方法:告诉Spring要使用哪种数据库访问技术
      1. 在spring配置文件使用声明需要使用的数据库访问技术对应的事务管理器实现类
        1. eq:
  2. 说明需要事务的类型(TransactionDefinition)
    1. 事务的隔离级别(对应TransactionDefinition下定义的5个以**ISOLATION_**开头的常量)
      1. DEFAULT:采用DB默认事务隔离级别,Mysql为REPEATABLE_READ,Oracle为READ_COMMITTED
      2. **READ_UNCOMMITTED:**读未提交。未解决任何并发问题
      3. **READ_COMMITTED:**读已提交。解决脏读,存在不可重复读和幻读
      4. **REPEATABLE_READ:**可重复读。解决脏读、不可重复读,存在幻读
      5. **SERIALIZABLE:**串行化。不存在并发问题
    2. 事务的超时时间(TIMEOUT_DEFAULT):表示一个事务最长的执行时间,如果超时就回滚,单位:秒(整数值),默认-1不限时
    3. 事务的传播行为(有7个):控制业务方法是否有事务,有什么样的事务(对应TransactionDefinition下定义的7个以**PROPAGATION_**开头的常量)
      1. **PROPAGATION_REQUIRED:**指定的方法必须在事务内执行,若存在当前事务则加入,不存在则创建一个新事务(最常见的选择,也是Spring默认的事务传播行为)
      2. **PROPAGATION_REQUIRES_NEW:**总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事物执行完毕
      3. **PROPAGATION_SUPPORTS:**若存在当前事务就加入,不存在就以非事务方式执行
      4. PROPAGATION_MANDATORY
      5. PROPAGATION_NESTED
      6. PROPAGATION_NEVER
      7. PROPAGATION_NOT_SUPPORTED
  3. 事务提交、回滚时机
    1. 业务方法正确执行完毕,没有抛出异常,spring自动提交事务
    2. 业务方法执行过程中抛出了运行时异常(RuntimeException及其子类)或ERROR,spring自动回滚事务
    3. 业务方法执行过程中抛出了非运行时异常(主要是受查异常),也会提交事务
      1. 受查异常:写代码时必须要捕获的异常(IOException、SQLException…)

2、Spring事务处理方案

1、注解方案(适合中小型项目使用,本文重点介绍)

  1. Spring框架自己用AOP实现业务方法增加事务的功能,使用**@Transactional**注解添加事务
  2. @Transactional注解是Spring框架提供的注解,放在public方法上面,表示当前方法开启了事务
  3. 可以给@Transactional注解的属性赋值,表示具体的隔离级别、传播行为、异常信息等

2、使用aspectJ框架(适合大型项目)

​ 在Spring配置文件中声明类、方法需要的事务,达到业务方法和事务配置完全分离。一键跳转~


1、@Transactional属性
  1. **propagation:**事务传播行为。类型为Propagation枚举,默认值为Propagation.REQUIRED
  2. **isolation:**事务隔离级别。类型为Isolation枚举,默认值为Isolation.DEFAULT
  3. **readOnly:**设置该方法对数据库的操作是否是只读的。类型为boolean,默认值为false
  4. **timeout:**设置本操作与数据库连接的超时时限。单位为秒,类型为int,默认值为-1(无时限)
  5. **rollbackFor:**设置需要回滚的异常类。类型为Class[],默认值为空数组(只有一个异常类时可不用数组)
  6. **rollbackForClassName:**设置需要回滚的异常类名字。类型为String[],默认值为空数组(只有一个异常类名字时可不用数组)
  7. **notRollbackFor:**设置不需要回滚的异常类。类型为Class[],默认值为空数组(只有一个异常类时可不用数组)
  8. **notRollbackForClassName:**设置不需要回滚的异常类名字。类型为String[],默认值为空数组(只有一个异常类名字时可不用数组)

2、@Transactional的使用步骤
  1. 声明事务管理器对象

  2. 开启事务注解驱动

    1. 告诉spring框架爹要用注解的方式管理事务

    2. spring使用AOP机制,创建@Transactional所标注类的代理对象,给方法加入事务功能

    3. spring给业务方法加入事务:使用AOP环绕通知,运行方法前开启事务,运行方法后提交或回滚事务

      1. @Around(value = "execution(..)")
        Object myAround(){
            // TODO: Spring开启事务
            try{
                // TODO: 执行业务方法
                // TODO: Spring提交事务
            } catch(Exception e){
                // TODO: Spring回滚事务
            }
        }
        
  3. 在业务方法上加@Transactional注解


3、实现步骤
  1. 创建maven项目
  2. 加入maven依赖
    1. spring依赖
    2. mybatis依赖
    3. mysql驱动
    4. spring的事务依赖
    5. mybatis和spring集成依赖(mybatis官方提供的,用来在spring项目中创建mybatis的SqlSessionFactory、dao对象的)
  3. 创建实体类
  4. 创建dao接口及mapper文件
  5. 创建mybatis主配置文件
  6. 创建Service接口及实现类,属性包含dao
  7. 创建spring配置文件(声明mybatis对象交给spring创建)
    1. 数据源(dataSource)
    2. SqlSessionFactory
    3. Dao对象
    4. 声明自定义的service
  8. 创建测试类,获取service对象,通过service对象完成对数据库的访问

4、项目结构

*MySql-Table-goods

*MySql-Table-sale

pom.xml


  4.0.0

  hom.wang
  st-07-spring-trans
  1.0-SNAPSHOT

  
    UTF-8
    1.8
    1.8
  

  
    
      junit
      junit
      4.11
      test
    
    
      org.springframework
      spring-context
      5.3.18
    

    
    
      org.springframework
      spring-tx
      5.3.18
    
    
    
      org.springframework
      spring-jdbc
      5.3.18
    
    
    
      org.mybatis
      mybatis
      3.5.7
    
    
    
      org.mybatis
      mybatis-spring
      2.0.6
    
    
    
      mysql
      mysql-connector-java
      8.0.29
    
    
    
      com.alibaba
      druid
      1.2.6
    
  

  
    
    
      
        
        src/main/java
        
        
          ***.properties-->
        
        false
      
    
    
    
      
        maven-compiler-plugin
        3.8.1
        
          1.8
          1.8
        
      
    
  

data.Goods.java
package hom.wang.data;
import java.math.BigDecimal;
public class Goods {
    private String goodsId;
    private String goodsName;
    private Integer goodsAmount;
    private BigDecimal goodsPrice;
}
data.Sale.java
package hom.wang.data;
public class Sale {
    private Integer saleId;
    private String goodsId;
    private Integer saleNum;
}
dao.Goods.java
package hom.wang.dao;
import hom.wang.data.Goods;
public interface GoodsDao {
    int updateGoods(Goods goods);

    Goods selectGoodsById(Goods goods);
}
dao.GoodsMapper.xml




    
        update goods
        set goods_amount = #{goodsAmount}
        where goods_id = #{goodsId}
    

    
        
        
        
        
    

    


dao.SaleDao.java
package hom.wang.dao;
import hom.wang.data.Sale;
public interface SaleDao {
    int insertSale(Sale sale);
}
dao.SaleMapper.xml




    
        insert into sale(goods_id, sale_num) values(#{goodsId}, #{saleNum})
    


exce.NotEnoughException.java
package hom.wang.exce;

public class NotEnoughException extends RuntimeException {
    public NotEnoughException() {
    }
    public NotEnoughException(String message) {
        super(message);
    }
}
service.impl.BuyServiceImpl.java
package hom.wang.service.impl;

import hom.wang.dao.GoodsDao;
import hom.wang.dao.SaleDao;
import hom.wang.data.Goods;
import hom.wang.data.Sale;
import hom.wang.exce.NotEnoughException;
import hom.wang.service.BuyService;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class BuyServiceImpl implements BuyService {
    GoodsDao goodsDao;
    SaleDao saleDao;

    
    
    // 上面配置的都是默认值,故而直接使用@Transactional就可以
    @Transactional
    @Override
    public void buy(Sale sale) {
        System.out.println("============ buy start =============");

        // 1、判断库存是否充足
        Goods goods = new Goods();
        goods.setGoodsId(sale.getGoodsId());
        goods = goodsDao.selectGoodsById(goods);

        if(null == goods){
            throw new NullPointerException("编号[" + sale.getGoodsId() + "]商品不存在!");
        }

        if(goods.getGoodsAmount() < sale.getSaleNum()){
            throw new NotEnoughException("库存不足!");
        }

        // 2、减少库存
        goods.setGoodsAmount(goods.getGoodsAmount() - sale.getSaleNum());
        goodsDao.updateGoods(goods);

        // 3、增加销售记录
        saleDao.insertSale(sale);

        System.out.println("============ buy end =============");
    }

    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }

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




    
    
        
        
    

    
        
        
        

        
        
    

jdbc.properties
jdbc.url=jdbc:mysql://127.0.0.1:3306/ms_user
jdbc.username=root
jdbc.password=root
jdbc.maxActive=20
applicationContext.xml



    

    
    
        
        
        
        
        
    

    
    
        
        
    

    
    
        
        
        
        
    

    
        
        
    

    
    
    
        
        
    

    
    
    

MyTest.java
package hom.wang;
import hom.wang.data.Sale;
import hom.wang.service.BuyService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
    @Test
    public void test(){
        ApplicationContext ac = 
            new ClassPathXmlApplicationContext("applicationContext.xml");
        BuyService buyService = (BuyService) ac.getBean("buyService");
        //buyService的代理对象是:com.sun.proxy.$Proxy17,jdk动态代理对象
        System.out.println("buyService的代理对象是:" + buyService.getClass().getName());

        Sale sale = new Sale();
        sale.setGoodsId("p_yz_00002");
        sale.setSaleNum(1);

        buyService.buy(sale);
    }
}

*没错,最终结果正如你所预料的!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/946861.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号