15、Spring之基于xml的声明式事务

打印 上一主题 下一主题

主题 929|帖子 929|积分 2787

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

创建名为spring_transaction_xml的新module,过程参考13.1节
15.1.1、配置打包方式和依赖


注意:比起基于注解的声明式事务,基于xml的声明式事务还需要额外引入spring-AOP的依赖
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.    
  4.     <context:component-scan base-package="org.rain.spring"></context:component-scan> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.    
  6.     <context:component-scan base-package="org.rain.spring"></context:component-scan> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  7.     <modelVersion>4.0.0</modelVersion>
  8.     <groupId>org.rain</groupId>
  9.     <artifactId>spring_transaction_xml</artifactId>
  10.     <version>1.0-SNAPSHOT</version>
  11.     <packaging>jar</packaging>
  12.     <dependencies>
  13.    
  14.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  15.    
  16.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  17.    
  18.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>org.springframework</groupId>
  19.    
  20.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>spring-context</artifactId>
  21.    
  22.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>5.3.1</version>
  23.    
  24.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  25.    
  26.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  27.    
  28.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  29.    
  30.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  31.    
  32.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  33.    
  34.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>org.springframework</groupId>
  35.    
  36.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>spring-orm</artifactId>
  37.    
  38.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>5.3.1</version>
  39.    
  40.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  41.    
  42.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  43.    
  44.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  45.    
  46.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>org.springframework</groupId>
  47.    
  48.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>spring-test</artifactId>
  49.    
  50.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>5.3.1</version>
  51.    
  52.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  53.    
  54.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  55.    
  56.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  57.    
  58.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>org.springframework</groupId>
  59.    
  60.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>spring-aspects</artifactId>
  61.    
  62.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>5.3.1</version>
  63.    
  64.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  65.    
  66.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  67.    
  68.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  69.    
  70.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>junit</groupId>
  71.    
  72.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>junit</artifactId>
  73.    
  74.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>4.12</version>
  75.    
  76.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <scope>test</scope>
  77.    
  78.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  79.    
  80.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  81.    
  82.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  83.    
  84.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>mysql</groupId>
  85.    
  86.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>mysql-connector-java</artifactId>
  87.    
  88.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>5.1.49</version>
  89.    
  90.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  91.    
  92.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  93.    
  94.     <context:component-scan base-package="org.rain.spring"></context:component-scan><dependency>
  95.    
  96.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <groupId>com.alibaba</groupId>
  97.    
  98.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <artifactId>druid</artifactId>
  99.    
  100.     <context:component-scan base-package="org.rain.spring"></context:component-scan>    <version>1.0.31</version>
  101.    
  102.     <context:component-scan base-package="org.rain.spring"></context:component-scan></dependency>
  103.     </dependencies>
  104. </project>
复制代码
15.1.2、创建jdbc.properties文件

  1. jdbc.driver=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8
  3. jdbc.username=root
  4. jdbc.password=root
复制代码
15.1.3、创建Spring的配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:context="http://www.springframework.org/schema/context"
  5.        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">
  6.    
  7.     <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
  8.    
  9.     <bean id="datasource" >
  10.    
  11.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  12.    
  13.     <context:component-scan base-package="org.rain.spring"></context:component-scan><property name="driverClassName" value="${jdbc.driver}"></property>
  14.    
  15.     <context:component-scan base-package="org.rain.spring"></context:component-scan><property name="url" value="${jdbc.url}"></property>
  16.    
  17.     <context:component-scan base-package="org.rain.spring"></context:component-scan><property name="username" value="${jdbc.username}"></property>
  18.    
  19.     <context:component-scan base-package="org.rain.spring"></context:component-scan><property name="password" value="${jdbc.password}"></property>
  20.     </bean>
  21.    
  22.     <bean id="jdbcTemplate" >
  23.    
  24.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
  25.    
  26.     <context:component-scan base-package="org.rain.spring"></context:component-scan><property name="dataSource" ref="datasource"></property>
  27.     </bean>
  28. </beans>
复制代码
15.1.4、创建持久层接口BookDao及其实现类

  1. package org.rain.spring.dao;
  2. /**
  3. * @author liaojy
  4. * @date 2023/9/3 - 17:34
  5. */
  6. public interface BookDao {
  7.     /**
  8.      * 查询图书的价格
  9.      * @param bookId
  10.      * @return
  11.      */
  12.     Integer getPriceByBookId(Integer bookId);
  13.     /**
  14.      * 更新图书的库存
  15.      * @param bookId
  16.      */
  17.     void updateStockOfBook(Integer bookId);
  18.     /**
  19.      * 更新用户的余额
  20.      * @param userId
  21.      * @param price
  22.      */
  23.     void updateBalanceOfUser(Integer userId,Integer price);
  24. }
复制代码
  1. package org.rain.spring.dao.impl;
  2. import org.rain.spring.dao.BookDao;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.jdbc.core.JdbcTemplate;
  5. import org.springframework.stereotype.Repository;
  6. /**
  7. * @author liaojy
  8. * @date 2023/9/3 - 17:36
  9. */
  10. @Repository
  11. public class BookDaoImpl implements BookDao {
  12.     @Autowired
  13.     private JdbcTemplate jdbcTemplate;
  14.     public Integer getPriceByBookId(Integer bookId) {
  15.    
  16.     <context:component-scan base-package="org.rain.spring"></context:component-scan>String sql = "select price from t_book where book_id = ?";
  17.    
  18.     <context:component-scan base-package="org.rain.spring"></context:component-scan>Integer price = jdbcTemplate.queryForObject(sql, Integer.class,bookId);
  19.    
  20.     <context:component-scan base-package="org.rain.spring"></context:component-scan>return price;
  21.     }
  22.     public void updateStockOfBook(Integer bookId) {
  23.    
  24.     <context:component-scan base-package="org.rain.spring"></context:component-scan>String sql = "update t_book set stock = stock -1 where book_id = ?";
  25.    
  26.     <context:component-scan base-package="org.rain.spring"></context:component-scan>jdbcTemplate.update(sql, bookId);
  27.     }
  28.     public void updateBalanceOfUser(Integer userId, Integer price) {
  29.    
  30.     <context:component-scan base-package="org.rain.spring"></context:component-scan>String sql = "update t_user set balance = balance - ? where user_id = ?";
  31.    
  32.     <context:component-scan base-package="org.rain.spring"></context:component-scan>jdbcTemplate.update(sql,price,userId);
  33.     }
  34. }
复制代码
15.1.5、创建业务层接口BookService及其实现类

  1. package org.rain.spring.service;
  2. /**
  3. * @author liaojy
  4. * @date 2023/9/3 - 17:52
  5. */
  6. public interface BookService {
  7.     void buyBook(Integer bookId,Integer userId);
  8. }
复制代码
  1. package org.rain.spring.service.impl;
  2. import org.rain.spring.dao.BookDao;
  3. import org.rain.spring.service.BookService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Service;
  6. /**
  7. * @author liaojy
  8. * @date 2023/9/3 - 17:53
  9. */
  10. @Service
  11. public class BookServiceImpl implements BookService {
  12.     @Autowired
  13.     private BookDao bookDao;
  14.     public void buyBook(Integer bookId, Integer userId) {
  15.    
  16.     <context:component-scan base-package="org.rain.spring"></context:component-scan>//查询图书的价格
  17.    
  18.     <context:component-scan base-package="org.rain.spring"></context:component-scan>Integer price = bookDao.getPriceByBookId(bookId);
  19.    
  20.     <context:component-scan base-package="org.rain.spring"></context:component-scan>//更新图书的库存
  21.    
  22.     <context:component-scan base-package="org.rain.spring"></context:component-scan>bookDao.updateStockOfBook(bookId);
  23.    
  24.     <context:component-scan base-package="org.rain.spring"></context:component-scan>//更新用户的余额
  25.    
  26.     <context:component-scan base-package="org.rain.spring"></context:component-scan>bookDao.updateBalanceOfUser(userId,price);
  27.     }
  28. }
复制代码
15.1.6、创建控制层BookController


注意:因为控制层没用到接口,所以方法的访问修饰符要手动设置
  1. package org.rain.spring.controller;
  2. import org.rain.spring.service.BookService;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Controller;
  5. /**
  6. * @author liaojy
  7. * @date 2023/9/3 - 17:54
  8. */
  9. @Controller
  10. public class BookController {
  11.     @Autowired
  12.     private BookService bookService;
  13.     public void buyBook(Integer bookId, Integer userId){
  14.    
  15.     <context:component-scan base-package="org.rain.spring"></context:component-scan>bookService.buyBook(bookId,userId);
  16.     }
  17. }
复制代码
15.1.7、配置对注解组件的扫描

  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
15.2、基于xml事务的实现

15.2.1、配置事务管理器

  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  3.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  4.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
15.2.2、配置事务通知


注意:tx:advice标签导入的名称空间需要 tx 结尾的那个
  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
15.2.3、配置事务通知作用到连接点

  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  3.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  4.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
15.2.4、配置事务通知的属性


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

  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  3.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  4.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  5.     <context:component-scan base-package="org.rain.spring"></context:component-scan>   
  6.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
15.3、测试事务的效果

15.3.1、创建测试类

模拟场景:


  • 用户购买图书,先查询图书的价格,再更新图书的库存和用户的余额
  • 假设id为1的用户(余额为50),购买id为1的图书(价格为80)
  • 购买图书之后,用户的余额应为-30;但由于数据库中余额字段设置了无符号,因此无法将-30插入到余额字段;
    此时执行更新用户余额的sql语句会抛出异常
  1. 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(){   
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>bookController.buyBook(1,1);    }}
复制代码
15.3.2、执行前的数据


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

此时id为1的用户余额为50
15.3.3、执行时的异常


15.3.3、执行后的数据


由于使用了Spring的声明式事务,更新(图书)库存和更新(用户)余额,要么都成功,要么都失败;
本例属于都失败,所以(图书)库存和(用户)余额都没有变化

15.4、配置事务的属性


事务属性的详细作用,请参考14.5节
  1.    
  2.     <context:component-scan base-package="org.rain.spring"></context:component-scan>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

商道如狼道

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表