[000-01-010].第15节:Spring对事务的支持

我的后端学习大纲

我Spring学习大纲


1.银行转账情景体验事务:

1.1.环境搭建:

a.第一步:建库建表:

在这里插入图片描述
在这里插入图片描述

b.第二步:建模块引依赖:

本次操作连接数据库的技术先使用JdbcTemplate,先不集成MyBatis

  • 1.引入依赖:
<?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-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--spring jdbc-->
        <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>

c.第三步:编写持久层:

  • 1.持久层的接口:
package com.atguigu.spring5.dao;
public interface UserDao {
   
}
  • 2.持久层的实现类:
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {

}

d.第四步:创编写业务层

  • 在service中注入dao
package com.atguigu.spring5.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
	//在service中注入dao
    @Autowired
    private UserDao userDao;
}
  • 在dao中注入JdbcTemplate
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
 	@Autowired
    private JdbcTemplate jdbcTemplate;
}

e.第五步:编写Spring配置文件

  • 在JdbcTemplate注入DataSource
<?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:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 组件扫描 -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db" />
        <property name="username" value="root" />
        <property name="password" value="root" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
</beans>

f.实现转账功能:

然后在持久层dao中创建两个方法:多钱和少钱的方法;在Service创建转账的方法

  • 1.UserDao接口中创建抽象方法
package com.atguigu.spring5.dao;
public interface UserDao {
    //多钱
    public void addMoney();
    
    //少钱
    public void reduceMoney();
}
  • 2.在UserDaoImpl实现两个抽象方法
package com.atguigu.spring5.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //lucy转账100给mary
    //少钱
    @Override
    public void reduceMoney() {
    	String sql = "update t_account set money=money-? where username=?";
    	//调用jdbcTemplate模板中的update方法
        jdbcTemplate.update(sql,100,"lucy");
    }
    //多钱
    @Override
    public void addMoney() {
        String sql = "update t_account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"mary");
    }
}
  • 3.在service业务逻辑层实现转账。调用dao
package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;

    //转账的方法
    public void accountMoney() {
		
		//第二步 进行业务操作
        //lucy少100
        userDao.reduceMoney();
        
        //mary多100
        userDao.addMoney();
    }
}

g.测试转账方法:

package com.atguigu.spring5.test;
import com.atguigu.spring5.config.TxConfig;
import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.lang.Nullable;

public class TestBook {
    @Test
    public void testAccount() {
        ApplicationContext context =  new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }   
}

h.上述实现过程可能出现的问题分析

  • 1.当执行完addmoney后,若出现突然断电或者中间代码有其他什么异常,那么就会导致无法执行reduceMoeny(),这样就破坏了事务的一致性原则。所以需要在这里处理下,保证事务的一致性。
    在这里插入图片描述
  • 2.以银行转账来说明,要么都成功,要么都失败
    在这里插入图片描述

i.下面代码是对上述问题的解决思路。

package com.atguigu.spring5.service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;
    //转账的方法
    public void accountMoney() {
		try {
            //第一步 开启事务
            
            //第二步 进行业务操作
            //lucy少100
            userDao.reduceMoney();

            //模拟异常
            int i = 10/0;
            
            //mary多100
            userDao.addMoney();

            //第三步 没有发生异常,提交事务
		}catch(Exception e) {
            //第四步 出现异常,事务回滚
	   }
    }
}

2.事务相关:

2.1.事务的概述:

a.什么是事务Transaction(tx)

  • 事务就是数据库操作最基本单元,是逻辑上一组操作,要么都成功,如果有一个失败,则所有操作都失败

b.Spring中事务实现方式:

  • 1.编程式事务:
    • 通过编写代码的方式来实现事务的管理。
  • 2.声明式事务:
    • 基于注解方式
    • 基于XML配置方式

c.事务的四个处理过程:

  • 1.第一步:开启事务 (start transaction)
  • 2.第二步:执行核心业务代码
  • 3.第三步:提交事务(如果核心业务处理过程中没有出现异常)(commit transaction)
  • 4.第四步:回滚事务(如果核心业务处理过程中出现异常)(rollback transaction)

d.事务四个特性(ACID)

  • 1.原子性: 所谓的原子性就是不可以再分了,就是操作后要么都成功,要么都是失败的
  • 2.一致性:操作前后的总额或者总数不变化。如金额,总的来说都是200元钱,不会变多变少。
  • 3.隔离性: 隔离性就是:操作同一个东西的时候,双方的操作不受一方的影响
  • 4.持久性: 数据的存储

e.事务典型场景:

  • 1.银行转账:lucy 转账 100 元 给 mary;lucy 少 100,mary 多 100;当双方有一个人金额没有变化的时候,那么双方的金额都不可以变化。这就是事务

2.2.MVC中引入事务场景:

  • 1.事务操作一般就是添加到三层架构中的Service层(业务逻辑层)
    在这里插入图片描述

3.Spring对事务的支持:

在Spring进行声明式进行事务管理,其底层使用的是AOP原理

3.1.Spring事务管理API

  • 1.提供了一个接口,代表事务管理器接口,这个接口针对不同的框架提供了不同的实现类
    在这里插入图片描述
  • 2.PlatformTransactionManager接口:spring事务管理器的核心接口。在Spring6中它有两个实现:
    • DataSourceTransactionManager:支持JdbcTemplate、MyBatis、Hibernate等事务管理。
    • JtaTransactionManager:支持分布式事务管理
  • 3.如果要在Spring6中使用JdbcTemplate,就要使用DataSourceTransactionManager来管理事务。(Spring内置写好了,可以直接用

3.2.声明式事务之注解方式:

a.在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"
       xmlns:aop="http://www.springframework.org/schema/aop"
<!--在Spring配置文件中引入名称空间tx-->    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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 组件扫描 -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db" />
        <property name="username" value="root" />
        <property name="password" value="root" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

c.在service类上面(或者service类中的某个方法上面)添加事务注解

  • 1.@Transactional:这个注解添加到类上面,也可以添加到方法上面
  • 2.如果类添加到注解上面:这个类里面所有的方法都添加事务了
  • 3.如果这个注解添加到某个方法上面,只是为这个方法添加了事务。
@Service
@Transactional
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;
    //后面的代码忽略了..........
}

d.@Transactional都有哪些属性:

在这里插入图片描述

  • 1.事务中的重点属性:
    • 事务传播行为
    • 事务隔离级别
    • 事务超时
    • 只读事务
    • 设置出现哪些异常回滚事务
    • 设置出现哪些异常不回滚事务

e.@Transactional中的重点属性:

e1.事务的传播行为propagation

1.什么是事务传播行为:

  • 1.在service类中有a()方法和b()方法,a()方法上有事务,b()方法上也有事务,当a()方法执行过程中调用了b()方法,事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为
    事务传播行为在spring框架中被定义为枚举类型
  • 2.一句话概括即:多事务方法直接进行调用,这个过程中事务是如何进行管理的

2.事务传播行为类型是怎么被定义的:

  • 1.事务传播行为在spring框架中被定义为枚举类型
    在这里插入图片描述

3.事务传播行为的值有哪些?

  • 1.REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】
  • 2.SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行【有就加入,没有就不管了】
  • 3.MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常【有就加入,没有就抛异常】
  • 4.REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】
  • 5.NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务【不支持事务,存在就挂起】
  • 6.NEVER:以非事务方式运行,如果有事务存在,抛出异常【不支持事务,存在就抛异常】
  • 7.NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样】
  • 在这里插入图片描述
    在这里插入图片描述

4.在代码中设置事务的传播行为:

@Transactional(propagation = Propagation.REQUIRED)

e2.ioslation:事务隔离级别:

1.什么是事务的隔离级别:

  • 1.事务隔离级别解决并发操作中出现的问题,隔离可以使得多事务之间的操作不受影响。
  • 2.事务隔离级别类似于教室A和教室B之间的那道墙,隔离级别越高表示墙体越厚。隔音效果越好。

2.数据库中读取数据存在的三大问题:(三大读问题)

  • 1.脏读:一个未提交的事务读取到了另一个未提交事务的数据
    在这里插入图片描述
  • 2.不可重复度:在同一个事务当中,第一次和第二次读取的数据不一样
    在这里插入图片描述
  • 3.幻读 :读到的数据是假的。

3.事务的隔离级别:通过设置隔离级别,可以解决读问题的三种情况

  • 1.读未提交:READ_UNCOMMITTED:
    • 这种隔离级别,存在脏读问题,所谓的脏读(dirty read)表示能够读取到其它事务未提交的数据
  • 2.读提交:READ_COMMITTED:
    • 解决了脏读问题,其它事务提交之后才能读到,但存在不可重复读问题
  • 3.可重复读:REPEATABLE_READ:
    • 解决了不可重复读,可以达到可重复读效果,只要当前事务不结束,读取到的数据一直都是一样的。但存在幻读问题
  • 4.序列化:SERIALIZABLE:
    • 解决了幻读问题,事务排队执行。不支持并发
      在这里插入图片描述

在Spring代码中如何设置隔离级别?

@Transactional(isolation = Isolation.READ_COMMITTED)

e3.timeout:事务超时超时时间

1.什么是超时时间:

  • 事务需要在一定时间内提交,如果不提交就回滚
  • 默认值是-1;设置时间是以秒为单位

设置事务的超时时间:

@Transactional(timeout = 10)
  • 1.以上代码表示设置事务的超时时间为10秒。
  • 2.表示超过10秒如果该事务中所有的DML语句还没有执行完毕的话,最终结果会选择回滚。
    默认值-1,表示没有时间限制。
  • 3.这里有个坑,事务的超时时间指的是哪段时间?在当前事务当中,最后一条DML语句执行之前的时间。如果最后一条DML语句后面很有很多业务逻辑,这些业务代码执行的时间不被计入超时时间。如下两个举例:
    • 以下代码的超时不会被计入超时时间
@Transactional(timeout = 10) // 设置事务超时时间为10秒。
public void save(Account act) {
    accountDao.insert(act);
    // 睡眠一会
    try {
        Thread.sleep(1000 * 15);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
  • 以下代码超时时间会被计入超时时间
@Transactional(timeout = 10) // 设置事务超时时间为10秒。
public void save(Account act) {
    // 睡眠一会
    try {
        Thread.sleep(1000 * 15);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    accountDao.insert(act);
}
  • 4.当如果想让整个方法的所有代码都计入超时时间的话,可以在方法最后一行添加一行无关紧要的DML语句
e4.readOnly:是否只读:

1.介绍:

  • 默认值是false
  • 可以自己设置值为true

2.设置只读:

@Transactional(readOnly = true)
  • 将当前事务设置为只读事务,在该事务执行过程中只允许select语句执行,delete insert update均不可执行
  • 该特性的作用是:启动spring的优化策略。提高select语句执行效率
  • 如果该事务中确实没有增删改操作,建议设置为只读事务
e5.rollbackFor:回滚:

1.概念:

  • 设置出现哪些异常可以进行事务的回滚

2.设置回滚:表示只有发生RuntimeException异常或该异常的子类异常才回滚。

@Transactional(rollbackFor = RuntimeException.class)
e6.noRollbackFor不回滚

1.概念:

  • 1.设置哪些事务可以不进行回滚

2.设置方式:表示发生NullPointerException或该异常的子类异常不回滚,其他异常则回滚。

@Transactional(noRollbackFor = NullPointerException.class)

3.3.事务的全注解式开发:

  • 1.创建配置类来代替配置文件:
package com.atguigu.spring5.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;

@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {

    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///user_db");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        //到ioc容器中根据类型找到dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  • 单元测试
    @Test
    public void testAccount2() {

        ApplicationContext context =
                new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }

3.4.声明式事务之XML实现方式:

a.在pom文件中添加依赖:

<!--aspectj依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>6.0.0-M2</version>
</dependency>

b.在 spring 配置文件中进行配置

  • 1.第一步 :配置事务管理器
 <!--1 创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
  • 2.第二步 :配置通知
<!--2 配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <!--name的值是方法名-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--name的值以account开头的都使用事务-->
            <!--<tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>
  • 3.第三步 :配置切入点和切面
<!--3 配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
  • 4.配置文件中的详细配置
<?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:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 组件扫描 -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db" />
        <property name="username" value="root" />
        <property name="password" value="root" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>

    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--1 创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--2 配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--<tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>

    <!--3 配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
</beans>
  • 5.更详细的配置文件中的配置
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.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>

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

    <!--配置通知-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="transfer*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
        </tx:attributes>
    </tx:advice>

    <!--配置切面-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.powernode.bank.service..*(..))"/>
        <!--切面 = 通知 + 切点-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

</beans>
  • 6.执行单元测试:
 @Test
    public void testAccount1() {

        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean2.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值