01-Spring中事务的实现和事务的属性

这篇具有很好参考价值的文章主要介绍了01-Spring中事务的实现和事务的属性。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

银行账户转账异常

需求: 实现act-001账户向act-002账户转账10000,要求两个账户的余额一个减成功一个加成功,即执行的两条update语句必须同时成功或失败

实现步骤

第一步: 引入项目所需要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>spring6-013-tx-bank</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <!--仓库-->
    <repositories>
        <!--spring里程碑版本的仓库-->
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <!--依赖-->
    <dependencies>
        <!--spring context,关联引入AOP-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--spring jdbc(Spring框架的JdbcTemplate),关联引入了事务相关的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!--德鲁伊连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.13</version>
        </dependency>
       	<!--@Resource注解-->
        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

第二步: 准备t_act表并向表中插入两条账户记录act-001和act-002

01-Spring中事务的实现和事务的属性,事务,spring,java,后端,事务的属性,Spring事务的实现

第三步: 编写t_act表对应的实体类

@Date
public class Account {
    private String actno;
    private Double balance;
}

第四步: 编写Dao(持久层)中的AccountDao接口及其实现类AccountDaoImpl专门负责t_act表的CRUD操作, 没有任何业务逻辑代码

public interface AccountDao {
    // 根据账号查询余额
    Account selectByActno(String actno);
    // 	更新账户信息
    int update(Account act);
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Override
    public Account selectByActno(String actno) {
        // 根据账号查询账户的信息,并把查询结果封装到对应的实体类中
        String sql = "select actno, balance from t_act where actno = ?";
        Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno);
        return account;
    }

    @Override
    public int update(Account act) {
        // 根据账号更新账户的余额
        String sql = "update t_act set balance = ? where actno = ?";
        int count = jdbcTemplate.update(sql, act.getBalance(), act.getActno());
        return count;
    }
}

第五步: 编写Service(业务层)中的AccountService及其实现类AccountServiceImpl专门负责关于账户的业务逻辑处理,如事务控制的相关代码

public interface AccountService {
    // 转账方法
    void transfer(String fromActno, String toActno, double money);
}
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    // 因为在这个方法中要完成所有的转账业务,所以需要控制事务
    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 如果余额充足开始转账
        Account toAct = accountDao.selectByActno(toActno);
        // 将内存中两个对象的余额先修改
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        
        // 将数据库账户的余额更新
        int count = accountDao.update(fromAct);
        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }
    }
}

第六步: 编写spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--组件扫描-->
    <context:component-scan base-package="com.powernode.bank"/>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

第七步: 编写测试程序,模拟表示/控制层处理用户的需求,后台调用对应业务层完成业务

public class BankTest {
    @Test
    public void testTransfer(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        try {
            accountService.transfer("act-001", "act-002", 10000);
            System.out.println("转账成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

第八步: 模拟转账异常,如果在更新两个账户余额的操作中出现了异常,此时就会出现前者的余额减了但后者的余额没有加上

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;

    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 余额充足,开始转账
        Account toAct = accountDao.selectByActno(toActno);
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        int count = accountDao.update(fromAct);
        
        // 模拟异常
        String s = null;
        s.toString();

        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }    
    }
}

Spring事务的实现

编程式事务

编程式事务(了解),自己在业务方法中手写控制事务的代码

@Override
public void transfer(String fromActno, String toActno, double money) {
    // 第一步开启事务

    // 第二步执行核心业务逻辑

    // 第三步如果执行核心业务流程中没有异常则提交事务
    
    // 第四步如果执行核心业务流程中有异常则回滚事务
}

声明式事务

声明式事务(常用),基于注解方式XML配置方式实现事务的控制

Spring事务管理的底层是基于AOP实现的,所以Spring专门针对事务开发了一套APIPlatformTransactionManager(事务管理器的核心接口)并且有两个实现类

实现类 描述
DataSourceTransactionManager 支持JdbcTemplate、MyBatis、Hibernate等事务管理
JtaTransactionManager 支持分布式事务管理

第一步: 在spring配置文件中引入tx的命名空间及其约束文件,spring-jdbc依赖中关联了事务相关的依赖

第二步:在spring配置文件中配置事务管理器,如果在Spring6中使用JdbcTemplate就要使用DataSourceTransactionManager事务管理器来管理事务

  • 由于事务管理器DataSourceTransactionManager底层利用的还是Connection连接连接对象开启关闭事务,所以需要给事务管理器配置数据源

第三步: 在spring配置文件中开启事务注解驱动器告诉Spring框架采用注解的方式控制事务

  • 事务管理器就是我们的切面类,@Transactional注解所标识的方法就是连接点(可以织入切面的位置)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">  
    <!--组件扫描-->
    <context:component-scan base-package="com.powernode.bank"/>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
     <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--开启事务注解驱动器告诉Spring框架采用注解的方式控制事务-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

第四步: 在Service层中的业务类上或业务方法上添加@Transactional注解,表示当前类/方法开启了事务,业务方法中批量的DML操作可以保证同时成功或失败文章来源地址https://www.toymoban.com/news/detail-745428.html

  • 在业务类上添加注解: 表示该类中所有的方法都开启事务
  • 在业务方法上添加注解: 表示只有当前方法开启事务
@Service("accountService")
@Transactional// 开启事务
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    @Override
    public void transfer(String fromActno, String toActno, double money) {
        // 查询账户余额是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("账户余额不足");
        }
        // 余额充足,开始转账
        Account toAct = accountDao.selectByActno(toActno);
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        int count = accountDao.update(fromAct);

        // 模拟异常
        String s = null;
        s.toString();

        count += accountDao.update(toAct);
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行");
        }
    }
}

到了这里,关于01-Spring中事务的实现和事务的属性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Spring——Spring事务的实现方式及传播特性

    Spring事务的特性及隔离级别同事务,详情请见 事务——什么是事务,事务的特性,事务的隔离级别_醉酒的戈多的博客-CSDN博客 在使用Spring框架的时候,有以下两种事务的实现方式: 编程式事务:用户自己通过代码来控制事务的处理逻辑 声明式事务:通过@Transactional注解来实

    2024年02月13日
    浏览(14)
  • Java后端07(Spring)

    ​涉及的设计模式:单例模式,简单工厂模式,代理模式,观察者模式,反射,注解。。。。。 ​在传统模式下,对象的创建和赋值,都是由开发者自己手动完成,事实情况下,开发者只关心如何获取赋值好的对象,但是并不希望自己手动进行创建对象和赋值的事情(sprin

    2024年02月13日
    浏览(11)
  • 【Spring】事务实现原理

    【Spring】事务实现原理

    在使用事务的时候需要添加@EnableTransactionManagement注解来开启事务,Spring事务底层是通过AOP来实现的,所以启用事务后,同样会向容器中注入一个代理对象创建器,AOP使用的是AnnotationAwareAspectJAutoProxyCreator,事务使用的是InfrastructureAdvisorAutoProxyCreator。 Advice通知:定义在切点上

    2024年02月05日
    浏览(6)
  • spring事务和数据库事务是怎么实现

    Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务

    2024年02月13日
    浏览(15)
  • Java后端07(Spring未完成)

    ​涉及的设计模式:单例模式,简单工厂模式,代理模式,观察者模式,反射,注解。。。。。 ​在传统模式下,对象的创建和赋值,都是由开发者自己手动完成,事实情况下,开发者只关心如何获取赋值好的对象,但是并不希望自己手动进行创建对象和赋值的事情(sprin

    2024年02月14日
    浏览(15)
  • 60.Spring事务实现基本原理

    60.Spring事务实现基本原理

    1.解析切面 —— bean的创建前第一个bean的后置处理器进行解析advisor(pointcut(通过@Transacational解析的切点) , advise) (这个advisor 是通过@EnableTransactionManagement注册了一个配置类,该配置类就配置了adivsor) 2.创建动态代理—— bean的初始化后调用bean的后置处理器进行创建动态代理(有

    2024年01月20日
    浏览(5)
  • 【Spring全家桶系列】Spring中的事务管理(基于注解完成实现)

    【Spring全家桶系列】Spring中的事务管理(基于注解完成实现)

    ⭐️ 前面的话 ⭐️ 本文已经收录到《Spring框架全家桶系列》专栏,本文将介绍Spring中的事务管理,事务的概念与作用,以及Spring事务的属性和传播机制。 📒博客主页:未见花闻的博客主页 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📌本文由 未见花闻 原创, CSDN 首发! 📆首

    2024年02月07日
    浏览(11)
  • 【Java学习】 Spring的基础理解 IOC、AOP以及事务

    【Java学习】 Spring的基础理解 IOC、AOP以及事务

        官网: https://spring.io/projects/spring-framework#overview     官方下载工具: https://repo.spring.io/release/org/springframework/spring/     github下载: https://github.com/spring-projects/spring-framework     maven依赖: 1.spring全家桶的结构构图:              最下边的是测试单元   其中spring封装

    2024年02月09日
    浏览(20)
  • 【JavaEE】Spring事务-事务的基本介绍-事务的实现-@Transactional基本介绍和使用

    【JavaEE】Spring事务-事务的基本介绍-事务的实现-@Transactional基本介绍和使用

    【JavaEE】Spring 事务(1) 比如跟钱相关的两个操作: 第一步操作:小马卡里 - 100元 第二步操作:老马卡里 + 100元 这就是一个事务,捆在一起的一组行为,就是事务 而它能保证的是,这个行为的原子性,一致性,隔离性,持久性: 两个操作都成功 两个操作都失败 要么一起成

    2024年02月11日
    浏览(11)
  • JAVA后端开发面试基础知识(八)——Spring

    JAVA后端开发面试基础知识(八)——Spring

    Spring是一个轻量级Java开发框架 我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,比如说 Spring 支持 IoC(Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、

    2024年03月10日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包