阅读本文前,建议先阅读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. mescroll.js 使用

    mescroll.js 使用 附:点击查看中文文档 第一步:引入css和js // unpkg的CDN: <link rel="stylesheet" href=" ...

  2. 代码审计——基础(JAVAEE)

    JAVAEE 目录 JAVAEE 常见框架 Struct2(控制层) Hibernate(持久层(与数据库交互)(不用再写简单的sql语句,但是需要一些列复杂的配置文件))(全ORM模型) Sprin ...

  3. 机器学习笔记(2): Logistic 回归

    Logistic 回归是线性回归中一个很重要的部分. Logistic 函数: \[\sigma(x) = \frac {L} {1 + \exp(-k(x - x_0))} \] 其中: \(L\) ...

  4. Python 潮流周刊#54:ChatTTS 强大的文本生成语音模型

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  5. The sultion of P4959

    problem & blog 首先我们看到 \(x,y\) 有可能为负数,所以我们先把它旋转到第一象限. 然后我们发现如果 \(x_a \ge x_b\) 且 \(y_a \ge y_b\) ...

  6. 如果你也用过 struts2.简单介绍下 springMVC 和 struts2 的区别有哪些?

    a.springmvc 的入口是一个 servlet 即前端控制器,而 struts2 入口是一个 filter 过虑器. b.springmvc 是基于方法开发(一个 url 对应一个方法),请求参 ...

  7. 燕千云 YQCloud 数智化业务服务管理平台 发布1.13版本

    2022年6月10日,燕千云 YQCloud 数智化业务服务管理平台发布1.13版本.本次燕千云1.13版本新增了远程桌面.知识库多人在线协作.移动端疫苗核酸信息管理.单据委托代理.技能管理.产品自助 ...

  8. apisix~14在自定义插件中调用proxy_rewrite

    在 Apache APISIX 中,通过 proxy-rewrite 插件来修改上游配置时,需要确保插件的执行顺序和上下文环境正确.你提到在自己的插件中调用 proxy_rewrite.rewrite ...

  9. P5327 题解

    考虑把贡献摊到每个点上计算,每个点带来的贡献实际上是经过它的路径并大小,算完求和之后在除以 \(2\) 就得到了答案. 考虑怎么计算路径并大小. 考虑这样一个办法,将所有路径的起始点和终点按照 DFS ...

  10. 树莓派4B安装64位桌面版ubuntu20

    [准备] 硬件: 电脑.树莓派4B.显示器(hdmi线Micro HDMI转标准HDMI).鼠标.键盘.读卡器.TF卡.网线 软件:ubuntu20(x64桌面版).官方烧录工具Raspberry P ...