Spring中基于xml的声明式事务示例详解

 更新时间:2023年09月04日 09:19:53   作者:Javaer1995  
这篇文章主要介绍了Spring之基于xml的声明式事务,本文通过图文实例代码相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

15.1、环境搭建

创建名为spring_transaction_xml的新module,过程参考13.1节

15.1.1、配置打包方式和依赖

注意:比起基于注解的声明式事务,基于xml的声明式事务还需要额外引入spring-AOP的依赖

<?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>org.rain</groupId>
    <artifactId>spring_transaction_xml</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring IOC相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- Spring 持久化层相关 -->
        <!-- Spring 在执行持久化层操作、与持久化层技术进行整合过程中,需要使用orm、jdbc、tx三个jar包 -->
        <!-- 导入 orm 包就可以通过 Maven 的依赖传递性把其他两个也导入 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- Spring 测试相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- spring-AOP的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!-- 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
    </dependencies>
</project>

15.1.2、创建jdbc.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

15.1.3、创建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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
    <!-- 配置数据源 -->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--通过${key}的方式访问外部属性文件的value-->
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!-- 配置 JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 装配数据源 -->
        <property name="dataSource" ref="datasource"></property>
    </bean>
</beans>

15.1.4、创建持久层接口BookDao及其实现类

package org.rain.spring.dao;
/**
 * @author liaojy
 * @date 2023/9/3 - 17:34
 */
public interface BookDao {
    /**
     * 查询图书的价格
     * @param bookId
     * @return
     */
    Integer getPriceByBookId(Integer bookId);
    /**
     * 更新图书的库存
     * @param bookId
     */
    void updateStockOfBook(Integer bookId);
    /**
     * 更新用户的余额
     * @param userId
     * @param price
     */
    void updateBalanceOfUser(Integer userId,Integer price);
}

package org.rain.spring.dao.impl;
import org.rain.spring.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
 * @author liaojy
 * @date 2023/9/3 - 17:36
 */
@Repository
public class BookDaoImpl implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public Integer getPriceByBookId(Integer bookId) {
        String sql = "select price from t_book where book_id = ?";
        Integer price = jdbcTemplate.queryForObject(sql, Integer.class,bookId);
        return price;
    }
    public void updateStockOfBook(Integer bookId) {
        String sql = "update t_book set stock = stock -1 where book_id = ?";
        jdbcTemplate.update(sql, bookId);
    }
    public void updateBalanceOfUser(Integer userId, Integer price) {
        String sql = "update t_user set balance = balance - ? where user_id = ?";
        jdbcTemplate.update(sql,price,userId);
    }
}

15.1.5、创建业务层接口BookService及其实现类

package org.rain.spring.service;
/**
 * @author liaojy
 * @date 2023/9/3 - 17:52
 */
public interface BookService {
    void buyBook(Integer bookId,Integer userId);
}

package org.rain.spring.service.impl;
import org.rain.spring.dao.BookDao;
import org.rain.spring.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author liaojy
 * @date 2023/9/3 - 17:53
 */
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    public void buyBook(Integer bookId, Integer userId) {
        //查询图书的价格
        Integer price = bookDao.getPriceByBookId(bookId);
        //更新图书的库存
        bookDao.updateStockOfBook(bookId);
        //更新用户的余额
        bookDao.updateBalanceOfUser(userId,price);
    }
}

15.1.6、创建控制层BookController

注意:因为控制层没用到接口,所以方法的访问修饰符要手动设置

package org.rain.spring.controller;
import org.rain.spring.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
 * @author liaojy
 * @date 2023/9/3 - 17:54
 */
@Controller
public class BookController {
    @Autowired
    private BookService bookService;
    public void buyBook(Integer bookId, Integer userId){
        bookService.buyBook(bookId,userId);
    }
}

15.1.7、配置对注解组件的扫描

    <!--扫描注解组件-->
    <context:component-scan base-package="org.rain.spring"></context:component-scan>

15.2、基于xml事务的实现

15.2.1、配置事务管理器

<!--配置事务管理器-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 装配要进行事务管理的数据源 -->
        <property name="dataSource" ref="datasource"></property>
    </bean>

15.2.2、配置事务通知

注意:tx:advice标签导入的名称空间需要 tx 结尾的那个

    <!--
        tx:advice标签:配置事务通知
            id属性:给事务通知标签设置唯一标识,便于引用
            transaction-manager属性:通过id引用对应的事务管理器
    -->
    <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager"></tx:advice>

15.2.3、配置事务通知作用到连接点

    <aop:config>
        <!--
            通过切入点表达式,将事务通知作用到连接点
        -->
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* org.rain.spring.service.impl.*.*(..))"></aop:advisor>
    </aop:config>

15.2.4、配置事务通知的属性

注意:不使用tx:method标签指定的方法是不会使用事务的,为了让切入点表达式的所有方法都使用到事务,可以使用*通配符:<tx:method name="*"/>

        <tx:attributes>
            <!--
                tx:method标签:配置使用事务的方法
                    name属性:指定用事务的方法名,可以使用星号代表多个字符
            -->
            <tx:method name="buyBook"/>
        </tx:attributes>

15.3、测试事务的效果

15.3.1、创建测试类

模拟场景:

  • 用户购买图书,先查询图书的价格,再更新图书的库存和用户的余额
  • 假设id为1的用户(余额为50),购买id为1的图书(价格为80)
  • 购买图书之后,用户的余额应为-30;但由于数据库中余额字段设置了无符号,因此无法将-30插入到余额字段;此时执行更新用户余额的sql语句会抛出异常

package org.rain.spring.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.rain.spring.controller.BookController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
 * @author liaojy
 * @date 2023/9/4 - 0:20
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-tx-xml.xml")
public class TxByXml {
    @Autowired
    private BookController bookController;
    @Test
    public void testBuyBook(){
        bookController.buyBook(1,1);
    }
}

15.3.2、执行前的数据

此时id为1的图书库存为100

此时id为1的用户余额为50

15.3.3、执行时的异常

15.3.3、执行后的数据

由于使用了Spring的声明式事务,更新(图书)库存和更新(用户)余额,要么都成功,要么都失败;

本例属于都失败,所以(图书)库存和(用户)余额都没有变化

15.4、配置事务的属性

事务属性的详细作用,请参考14.5节

 <!-- rollback-for属性:设置回滚的异常 -->
 <!-- no-rollback-for属性:设置不回滚的异常 -->
 <!-- isolation属性:设置事务的隔离级别 -->
 <!-- timeout属性:设置事务的超时属性 -->
 <!-- propagation属性:设置事务的传播行为 -->
 <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
 <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
 <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>

到此这篇关于Spring之基于xml的声明式事务的文章就介绍到这了,更多相关spring 声明式事务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java List按照某字段去重的使用示例

    Java List按照某字段去重的使用示例

    在Java开发中,我们经常会面临对List中对象属性去重的需求,本文主要介绍了Java List按照某字段去重的使用示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • Springboot之idea之pom文件图标不对问题

    Springboot之idea之pom文件图标不对问题

    这篇文章主要介绍了Springboot之idea之pom文件图标不对问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 浅谈Java并发中ReentrantLock锁应该怎么用

    浅谈Java并发中ReentrantLock锁应该怎么用

    本文主要介绍了ava并发中ReentrantLock锁的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Java计算程序代码执行时间的方法小结

    Java计算程序代码执行时间的方法小结

    这篇文章主要介绍了Java计算程序代码执行时间的方法,结合实例形式总结分析了java采用毫秒数及纳秒数计算程序运行时间的相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • Java 实战项目之在线点餐系统的实现流程

    Java 实战项目之在线点餐系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+SSM+jsp+mysql+maven实现在线点餐系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • Java 客户端操作 FastDFS 实现文件上传下载替换删除功能

    Java 客户端操作 FastDFS 实现文件上传下载替换删除功能

    这篇文章主要介绍了Java 客户端操作 FastDFS 实现文件上传下载替换删除功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • 微服务Springcloud之Feign的基本使用

    微服务Springcloud之Feign的基本使用

    这篇文章主要介绍了微服务Springcloud之Feign的基本使用,Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解,需要的朋友可以参考下
    2023-03-03
  • SpringBoot如何通过配置文件(yml,properties)限制文件上传大小

    SpringBoot如何通过配置文件(yml,properties)限制文件上传大小

    这篇文章主要介绍了SpringBoot如何通过配置文件(yml,properties)限制文件上传大小,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Struts2学习手册之文件上传基础教程

    Struts2学习手册之文件上传基础教程

    Struts2提供的文件上传下载机制十分简便,使得我们写很少的代码,下面这篇文章主要给大家介绍了关于Struts2学习手册之文件上传的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-05-05
  • springboot封装响应实体的实例代码

    springboot封装响应实体的实例代码

    这篇文章主要介绍了springboot封装响应实体,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07

最新评论