Spring事务控制

发布时间:2024年01月09日

目录

1.事务介绍

1.1什么是事务?

1.2事务的特性

1.3数据库本身控制事物

1.4jdbc中使用事物

2.Spring中事务控制的API介绍

2.1.PlatformTransactionManager

2.2TransactionDefinition

2.2.1配置事务的属性

2.2.2事务隔离级别

2.2.3事务的传播行为

2.2.4事务超时

2.2.5读写性

2.2.6回滚规则

?2.3TransactionStatus

3.简单案例

3.1普通转账案例

3.2改造转账案例

4.动态代理控制事务

4.1步骤

4.2简单实操

5.Spring AOP控制事务

5.1步骤

5.2简单实操

6.基于注解的AOP控制事务

6.1配置步骤

6.2涉及到的注解


1.事务介绍

1.1什么是事务?

当你需要一次执行多条SQL语句时,可以使用事务。通俗一点说,如果这几条SQL语句全部执行成功,则才对数据库进行一次更新,如果有一条SQL语句执行失败,则这几条SQL语句全部不进行执行,这个时候需要用到事务。

1.2事务的特性

原子性(Atomicity)
? ? ? ?事务是最小的执行单位,不可再分割

一致性(Consistency)
? ? ? ?事务前后的数据都是正确的

隔离性(Isolation)
? ? ? 事物之间相互隔离,互不干扰(并发执行的事务彼此无法看到对方的中间状态)

持久性(Durability)
? ? ? ?事务一旦提交不可再回滚?

1.3数据库本身控制事物

start transaction;#记录log(老数据)
      //1.本地数据库操作:张三减少金额
      //2.本地数据库操作:李四增加金额
rollback; #根据log恢复老数据
或
commit; #删除log

1.4jdbc中使用事物

1.获取对数据库的连接

2.设置事务不自动提交(默认情况是自动提交的)

conn.setAutoCommit(false);   //其中conn是第一步获取的随数据库的连接对象。

3.把想要一次性提交的几个sql语句用事务进行提交

try{
    Statement stmt = null; 
    stmt =conn.createStatement(); 
    stmt.executeUpdate(sql1); 
    int a=6/0;
    stmt.executeUpdate(Sql2); 
    . 
    . 
    . 
    conn.commit();   //使用commit提交事务 
}

4.捕获异常,进行数据的回滚(回滚一般写在catch块中)

catch(Exception e) { 
   ... 
   conn.rollback(); 
}

2.Spring中事务控制的API介绍

  • 说明:

    • JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。

    • Spring框架为我们提供了一组事务控制的接口。具体在后面的小节介绍。这组接口是在spring-tx.RELEASE.jar中。

    • spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。

2.1.PlatformTransactionManager

此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法,源代码如下:

public interface PlatformTransactionManager { 
    
  	//开启事务  
    TransactionStatus getTransaction(TransactionDefinition definition) 
        						throws TransactionException; 
    //提交事务
    void commit(TransactionStatus status) throws TransactionException; 
    
  	//回滚事务
    void rollback(TransactionStatus status) throws TransactionException;   
} 

真正管理事务的对象:

Spring为不同的orm框架提供了不同的PlatformTransactionManager接口实现类:

  • DataSourceTransactionManager:使用Spring JDBC或iBatis 进行持久化数据时使用

  • HibernateTransactionManager:使用Hibernate版本进行持久化数据时使用

2.2TransactionDefinition

TransactionDefinition接口包含与事务属性相关的方法,源代码如下:

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;
    
    //传播行为
    int getPropagationBehavior();
	//隔离级别
    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();
}
  • TransactionDefinition 接口定义的事务规则包括:事务隔离级别、事务传播行为、事务超时、事务的只读、回滚规则属性,同时,Spring 还为我们提供了一个默认的实现类:DefaultTransactionDefinition,该类适用于大多数情况。如果该类不能满足需求,可以通过实现 TransactionDefinition 接口来实现自己的事务定义。

2.2.1配置事务的属性

  • isolation:用于指定事务的隔离级别。默认值是?DEFAULT,表示使用数据库的默认隔离级别。
  • propagation:用于指定事务的传播行为。默认值是?REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择?SUPPORTS
  • read-only:用于指定事务是否只读。只有查询方法才能设置为?true。默认值是false,表示读写。
  • timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
  • rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
  • no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。

代码示例:

<?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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/base_crud"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

    <!-- 1.配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 2.配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!-- 3.配置AOP -->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* cn.bruce.service.impl.*.*(..))"/>
	<!-- 4.建立事务通知和切入点表达式的对应关系 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

    <!-- 配置dao -->
    <bean id="accountDao" class="cn.bruce.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置service -->
    <bean id="accountService" class="cn.bruce.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

</beans>

2.2.2事务隔离级别

事务并发时的安全问题

问题描述隔离级别
脏读一个事务读取到另一个事务还未提交的数据read-commited
不可重复读一个事务内多次读取一行数据的内容,其结果不一致repeatable-read
幻读一个事务内多次读取一张表中的内容,其结果不一致serialized-read

Spring事务隔离级别(比数据库事务隔离级别多一个default)由低到高为:

隔离级别
ISOLATION_DEFAULT这是一个platfromtransactionmanager默认的隔离级别,使用数据库默认的事务隔离级别。
ISOLATION_READ_UNCOMMITTED这是事务最低的隔离级别,会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 Oracle数据库默认的隔离级别。
ISOLATION_REPEATABLE_READ这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。MySQL数据库默认的隔离级别。
ISOLATION_SERIALIZABLE这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

2.2.3事务的传播行为

  • 什么是事务传播行为?

    事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。 例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。

  • Spring定义了七种传播行为:

事务传播行为类型说明
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。

2.2.4事务超时

  • timeout事务超时时间: 当前事务所需操作的数据被其他事务占用,则等待。

    • 100:自定义等待时间100(秒)。

    • -1:由数据库指定等待时间,默认值。(建议)?

2.2.5读写性

  • readonly 读写性

    • true:只读,可提高查询效率,适合查询

    • false:可读可写,适合增删改

2.2.6回滚规则

TransactionAttribute

TransactionAttribute 的默认实现类是DefaultTransactionAttribute ,它同时继承了DefaultTransactionDefinition。在DefaultTransactionDefinition 的基础上增加了rollbackOn的实现,DefaultTransactionAttribute的实现指定了,当异常类型为unchecked exception 的情况下将回滚事务。

?

  • rollbackOn 回滚规则,可省略或设置 rollbackOn="Exception"

  • 如果事务中抛出 RuntimeException,则自动回滚

  • 如果事务中抛出 CheckException,不会自动回滚

?2.3TransactionStatus

PlatformTransactionManager.getTransaction(…) 方法返回一个 TransactionStatus 对象,该对象代表一个新的或已经存在的事务,源代码如下:

public  interface TransactionStatus{
   boolean isNewTransaction();
   void setRollbackOnly();
   boolean isRollbackOnly();
}

3.简单案例

写一个简单的转账案例:

3.1普通转账案例

添加转账业务

mapper:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.by.mapper.UserMapper">
    ... ...

	<!--转账-->
	<update id="updateUserOfSub">
		update t_user set money=money-#{money} where name=#{source}
	</update>

	<update id="updateUserOfAdd">
		update t_user set money=money+#{money} where name=#{target}
	</update>
</mapper>
public interface UserMapper {

    ... ...

    /**扣钱*/
    void updateUserOfSub(@Param("source") String source, @Param("money") Float money);
    /*加钱*/
    void updateUserOfAdd(@Param("target") String target, @Param("money") Float money);
}

service:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 转账
     * @param source
     * @param target
     * @param money
     */
    @Override
    public void updateUser(String source, String target, Float money) {
        userMapper.updateUserOfSub(source, money);
        int a = 6/0;
        userMapper.updateUserOfAdd(target, money);
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {
    @Autowired
    private UserService userService;
    /**
     * 转账业务
     */
    @Test
    public void testUpdate(){
        userService.updateUser("张三丰","宋远桥",1F);
    }
}

1.此时我们观察数据表里面的变化情况

?转账是成功的,但是涉及到业务的问题,如果业务层实现类有其中一个环节出问题,都会导致灾难。

2.我们先把数据恢复到转账前。

现在我们故意模拟转账业务出现问题

?

再来测试:

业务执行出错,但是!

这是因为:不满足事务的一致性(减钱的事务提交了,加钱的事务没有提交,甚至都没有执行到)。

3.2改造转账案例

applicationContext.xml:

 	<!--配置事物管理器-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置事物属性-->
    <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
        <property name="readOnly" value="false"></property>
    </bean>

service:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TransactionDefinition txDefinition;
    @Autowired
    private PlatformTransactionManager txManager;
    /**
     * 转账
     * @param source
     * @param target
     * @param money
     */
    @Override
    public void updateUser(String source, String target, Float money) {
        // 获取一个事务
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);
        try {

            userMapper.updateUserOfSub(source, money);
            int a = 6/0;
            userMapper.updateUserOfAdd(target, money);
            //提交事务
            txManager.commit(txStatus);
        }catch (Exception e){
            //回滚事务
            txManager.rollback(txStatus);
            e.printStackTrace();
        }
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {
    @Autowired
    private UserService userService;
    /**
     * 转账业务
     */
    @Test
    public void testUpdate(){
        userService.updateUser("张三丰","宋远桥",1F);
    }
}

事务回滚:

满足执行:

  • 我们现在虽然实现了事务控制,但是代码非常的臃肿,我们可以使用动态代理简化代码

4.动态代理控制事务

4.1步骤

动态代理是一种在运行时动态创建代理对象的技术,常用于AOP(面向切面编程)编程中。在事务管理中,动态代理可以用来控制事务的边界、传播和隔离级别。

以下是动态代理控制事务的一般过程:

  1. 定义接口:首先,定义一个接口,该接口定义了需要执行的方法。这些方法通常对应于业务逻辑的操作,如增删改查等。
  2. 创建代理对象:使用动态代理技术创建一个代理对象。代理对象实现了之前定义的接口,并拦截了接口方法的调用。
  3. 事务管理:在代理对象中实现事务管理逻辑。这通常包括开启事务、提交事务和回滚事务等操作。
  4. 方法拦截:在代理对象中拦截接口方法的调用。在方法调用之前,开启事务;在方法调用之后,根据方法的执行结果来决定是提交事务还是回滚事务。
  5. 异常处理:如果在方法执行过程中发生异常,可以根据异常类型和异常信息来决定是否回滚事务。
  6. 事务传播:可以根据需要设置事务的传播行为,例如,如果一个方法被另一个事务方法调用,可以设置事务的传播行为为“继续”或“新开”等。
  7. 事务隔离级别:可以根据需要设置事务的隔离级别,例如,是否允许一个事务看到其他事务修改但还未提交的数据等。

通过以上步骤,可以在不修改原有业务代码的情况下,利用动态代理技术实现对事务的管理和控制。

4.2简单实操

factory:

package com.by.factory;

import com.by.service.UserService;
import com.by.service.UserServiceImpl;
import org.hamcrest.Factory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * bean工厂
 */
@Component
public class BeanFactory {
    @Autowired
    private UserService userService;
    @Autowired
    private TransactionDefinition txDefinition;
    @Autowired
    private PlatformTransactionManager txManager;

    /**
     * 获得UserServiceImpl对象
     *
     * @return
     */
    public UserService getUserService() {
        return (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(),
            userService.getClass().getInterfaces(),
            new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args)
                        											throws Throwable {
                        //开启事务
                        TransactionStatus txStatus = 
                            txManager.getTransaction(txDefinition);
                        try {
                            method.invoke(userService, args);
                            //提交事务
                            txManager.commit(txStatus);
                        } catch (Exception e) {
                            //回滚事务
                            txManager.rollback(txStatus);
                            e.printStackTrace();
                        }
                        return null;
                    }
                });
    }
}

applicationContext.xml:

<!--配置service代理对象-->
<bean id="proxyService" factory-bean="beanFactory" factory-method="getUserService"></bean>

service:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 转账
     * @param source
     * @param target
     * @param money
     */
    @Override
    public void updateUser(String source, String target, Float money) {
        userMapper.updateUserOfSub(source, money);
        int a = 6/0;
        userMapper.updateUserOfAdd(target, money);
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class ServiceTest {
    @Autowired
    @Qualifier("proxyService")//注入代理对象
    private UserService userService;

    @Test
    public void testUpdate(){
        userService.updateUser("张三丰","宋远桥",1F);
    }
}
  • 事务回滚:

5.Spring AOP控制事务

5.1步骤

Spring AOP控制事务的步骤如下:

  1. 配置事务管理器:使用Spring的事务管理器来管理事务,确保事务的原子性、一致性、隔离性和持久性。
  2. 配置事务通知:使用@Transactional注解来配置事务通知,指定事务的传播行为、隔离级别、超时时间等属性。
  3. 建立切点和切面:使用Spring AOP的切点和切面来定义事务的边界,将事务管理逻辑与业务逻辑分离。
  4. 配置切入点表达式:通过配置切入点表达式来指定哪些方法需要被事务管理,以及事务的传播行为等。
  5. 异常处理:在事务方法中处理异常,根据异常类型和异常信息来决定是否回滚事务。
  6. 事务提交或回滚:根据方法执行结果来决定是提交事务还是回滚事务,确保数据的完整性和一致性。

通过以上步骤,可以使用Spring AOP来控制事务,确保业务逻辑与事务管理逻辑的分离,提高系统的可维护性和可扩展性。

5.2简单实操

导入schema约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!--配置事物属性
    <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
        <property name="readOnly" value="false"></property>
    </bean>

    配置service代理对象
    <bean id="proxyService" factory-bean="beanFactory" factory-method="getUserService"> 
    </bean>-->
</beans>    

配置增强

 <!-- 1、增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--事务属性-->
        <tx:attributes>
        <!-- 指定方法名称:是业务核心方法
            read-only:是否是只读事务。默认false,不只读。
            isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
            propagation:指定事务的传播行为。
            timeout:指定超时时间。默认值为:-1。永不超时。
            rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
						 省略时任何异常都回滚。
            -->
        <tx:method name="*" read-only="false" propagation="REQUIRED"/>
        <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
        <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
       </tx:attributes>
    </tx:advice>

配置切点

<aop:config>
        <!--2、切点-->
        <aop:pointcut expression="execution(* com.by.service.*.*(..))" id="pointcut"/>
    </aop:config>

配置切面

<aop:config>
        <!--3、切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

factory

删除bean工程

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//加载配置文件
public class ServiceTest {
    @Autowired
    private UserService userService;
    /**
     * 转账业务
     */
    @Test
    public void testUpdate(){
        userService.updateUser("张三丰","宋远桥",1F);
    }
}

事务回滚:

6.基于注解的AOP控制事务

6.1配置步骤

① 书写配置类

② 将对象注入到IoC容器中管理

③ 给业务添加事务注释,并指明事务属性

代码示例:

① 配置spring

@Configuration// 声明为配置类
@ComponentScan("cn.bruce")// 声明需要扫描的包
@Import({JdbcConfig.class, TransactionConfig.class})// 导入其他配置类
@PropertySource("jdbcConfig.properties")// 导入配置文件
@EnableAspectJAutoProxy(proxyTargetClass = true)// 开启注解支持
@EnableTransactionManagement// 开启事务控制
public class SpringConfiguration {
}

② 配置jdbc

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 创建数据源对象
     * @return
     */
    @Bean("dataSource")
    public DataSource creatDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * 创建JdbcTemplate
     * @param dataSource
     * @return
     */
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate creatJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

③ 配置事务控制器

public class TransactionConfig {

    /**
     * 用于创建事务管理器对象
     * @param dataSource
     * @return
     */
    @Bean(name = "transactionManager")
    public PlatformTransactionManager creatTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

④ 通过?@Repository?和?@service?注解将Dao和Service层对象注入IoC容器

⑤ 在业务层使用?@Transactional?注解进行事务配置

// 进行读写型事务配置
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
@Override
public void transfer(String sourceName, String targetName, Float money) {

    System.out.println("开始进行转账操作。。。");

    Account source = accountDao.getAccountByName(sourceName);

    Account target = accountDao.getAccountByName(targetName);

    source.setMoney(source.getMoney() - money);

    target.setMoney(target.getMoney() + money);

    accountDao.updateAccount(source);

    int i = 1/0;

    accountDao.updateAccount(target);

    System.out.println("转账完成。。。");
}

⑥ 书写测试类进行测试

6.2涉及到的注解

@Transactional?此注解相当于xml配置中的?<tx:attributes>****</tx:attributes>?用于进行事务的配置,其属性含义和xml中是一致的

此注解可是使用在接口、类和方法上:

  • 出现在接口上,表示此接口所有的实现类都有事务支持
  • 出现在类上,表示类所有的方法都有事务支持
  • 出现在方法上,表示此方法有事务支持
  • 以上三个位置的优先级:方法 > 类 > 接口

文章来源:https://blog.csdn.net/2301_77072336/article/details/135485540
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。