阅读本文前,建议先阅读Spring之基于注解的声明式事务

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"/>

15、Spring之基于xml的声明式事务的更多相关文章

  1. Spring中基于XML的声明式事务控制配置步骤

    1.配置事务管理器 2.配置事务的通知 此时,我们就需要导入事务的约束 tx名称空间和约束,同时也需要aop的 使用tx:advice标签配置事务通知 属性: id:给事务通知起一个唯一标识 tran ...

  2. spring基于XML的声明式事务控制

    <?xml version="1.0" encoding="utf-8" ?><beans xmlns="http://www.sp ...

  3. spring基于xml的声明式事务控制配置步骤

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  4. 阶段3 2.Spring_10.Spring中事务控制_6 spring基于XML的声明式事务控制-配置步骤

    环境搭建 新建工程 把对应的依赖复制过来 src下内容复制 配置spring中的声明事物 找到bean.xml开始配置 配置事物管理器 里面需要注入DataSource 2-配置事物通知 需要先导入事 ...

  5. 基于XML的声明式事务控制

    1.maven依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  6. spring基于注解的声明式事务控制

    package com.hope.service.impl;import com.hope.dao.IAccountDao;import com.hope.domain.Account;import ...

  7. Spring:(三) --常见数据源及声明式事务配置

    Spring自带了一组数据访问框架,集成了多种数据访问技术.无论我们是直接通过 JDBC 还是像Hibernate或Mybatis那样的框架实现数据持久化,Spring都可以为我们消除持久化代码中那些 ...

  8. 使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。

    使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务.

  9. Spring注解驱动开发之声明式事务

    前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...

  10. spring 事物(三)—— 声明式事务管理详解

    spring的事务处理分为两种: 1.编程式事务:在程序中控制事务开始,执行和提交:详情请点此跳转: 2.声明式事务:在Spring配置文件中对事务进行配置,无须在程序中写代码:(建议使用) 我对&q ...

随机推荐

  1. uniapp 跳转指定的tab导航页面

    考察的知识点:1.uniapp的页面跳转方法:uni.navigateTo2.页面跳转传值的方法:'?名称=值' 的方式3.参数的接收 onload(option){} 第一个页面的写法: toCom ...

  2. 纯css+html+js模仿elementui组件

    文件下载链接地址https://files.cnblogs.com/files/ht955/UIcomponents.zip?t=1717405975&download=true

  3. .NET5 .NET CORE 使用Apollo

    Apollo默认有一个"SampleApp"应用,"DEV"环境 和 "timeout" KEY. nuget 中下载 "Com. ...

  4. 玩转Zabbix智能告警:降噪、排班、认领、升级、IM协同

    Zabbix作为一款流行的企业级监控工具,可以监控各种网络设备和服务的状态,并提供强大的告警功能,能够在出现异常情况时及时通知管理员.以下是Zabbix的一些特点: 支持多种监控方式,包括SNMP.J ...

  5. ElasticSearch服务Java内存异常分析和排查解决

    ElasticSearch服务Java内存异常分析和排查解决 1.ElasticSearch业务微服务日志排查java.lang.IllegalStateException: Request cann ...

  6. spark读取写入jdbc.,Caused by: java.lang.NoSuchMethodException: org.apache.spark.sql.execution.datasources.jdbc.DriverWrapper.<init>()

    df.write .option("truncate", "true") .option("driver", mysqlDriver) .m ...

  7. 详解Web应用安全系列(3)失效的身份认证

    大多数身份和访问管理系统的设计和实现,普遍存在身份认证失效的问题.会话管理是身份验证和访问控制的基础,并且存在于所有有状态的应用程序中.攻击者可以使用指南手册来检测失效的身份认证,但通常会关注密码转储 ...

  8. HMS Core 6.2.0版本发布公告

    新增动作捕捉能力.通过简单拍摄即可获得人体3D骨骼关键点数据,广泛应用于虚拟形象.体育运动和医学分析等场景: 3D物体建模能力iOS版本上线. 查看详情>> 新增道路吸附能力.可根据坐标点 ...

  9. 海思SDK 学习 :001-HI_SDK 的 安装

    背景 保密.不管怎么样接触到了海思SDK的开发,作为一项比较常见的技术,我们开展有关地学习. host平台 :Ubuntu 16.04 arm平台 : 3531d arm-gcc :4.9.4 概况 ...

  10. arm linux 移植 ffmpeg 库 + x264 + x265

    背景 Ffmpeg 中带有h264的解码,没有编码,需要添加x264.libx264是一个自由的H.264编码库,是x264项目的一部分,使用广泛,ffmpeg的H.264实现就是用的libx264. ...