Spring的编程式事务和声明式事务

本文深入解析Spring事务管理机制,涵盖平台事务管理器、事务定义、事务状态等核心概念,详细阐述了事务传播行为及其实现方式,包括编程式事务管理和声明式事务管理,并通过转账示例展示了具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring事务管理的API

platfformTransactionManager 平台事务管理器
在这里插入图片描述
平台事务管理器: 接口 是spring用于管理事务的真正的对象
DataSourceTransactionManager: 底层使用JDBC管理事务
HibernateTransactionManager: 底层使用Hibernate管理事务

TransactionDefinition 事务定义信息
事务定义: 接口 是用于定义事务的相关信息 隔离级别 超时信息 传播行为 是否只读

TransactionStatus 事务的状态
事务的状态 用于记录在事务管理过程中 事务的状态的对象

API之间的关系

spring进行事务管理的时候,首先将平台事务管理器根据事务定义信息进行事务的管理 在事务管理过程中,产生各种状态,将这些状态记录到事务状态的对象中

spring的事务传播行为

事务传播行为产生的原因

一般事务发生在service层(会调用dao),为了解决复杂业务中业务层之间方法相互调用,而每个service又有自己的事务,一个业务中出现了多个事务,就出现了传播行为。
例A:

Class Dao1 {
	void da() {}
}
Class Dao2 {
	void db() {}
}

Class Service1 {
	@Autowired
	Dao1 dao;
	void sa() {
		dao.da()
	}
} 
Class Service2 {
	@Autowired
	Service2 service;
	@Autowired
	Dao2 dao2;
	void sb() {
		service.sa();
		dao2.db();
	}
}

我们可以看到在service1是有自己的事务的,service2也是有自己的事务的,那么就出现了sb方法中,一个业务两种事务,就产生了传播。

spring中提供了七种事务传播行为
保证多个操作在同一个事务中

下表中的含义根据上文中例A的代码来解释

传播行为含义
propagation_required默认值 如果sa中有事务 则使用sa中的事务,如果sa没有 创建一个新的事务 将操作(dao2.db)包含进来
propagation_supports支持事务, 如果sa中有事务,使用sa中的事务。如果sa没有事务 不使用事务
propagation_mandatory如果sa中有事务 使用sa中的事务 如果sa中没有事务 -抛异常
保证多个操作不再同一个事务中
传播行为含义
propagation_required_new如果sa中有事务,将sa中的事务挂起 创建新的事务 只包含自身操作 如果sa中没有事务 创建一个新的事务包含自身操作
propagation_not_support如果sa中有事务 将sa中的事务挂起 不再使用事务
propagation_never如果sa中有事务 报异常
嵌套式事务
传播行为含义
propagation_nested嵌套事务 如果sa中有事务,按照sa的事务执行,执行完成后,设置一个保存点 执行dao2.db()中的操作 如果没有异常 执行通过 如果有异常 可以选择回滚到最初的位置 也可以回滚到保存点

Spring中事务应用

以A给B转帐的例子来看事务,转帐这一个操作可以分为两个步骤:A的账户减少转帐金额,B的账户增加转帐金额,任何一个步骤出错,这一个操作都应该失败,这样理解起来AB转帐这个操作应该需要使用事务。

创建数据库的表
create table account (
    name char(20),
    money double(5,2)
);

编程式事务管理 —通过代码实现

第一步 在POM文件中引入环境相关的依赖
第二步 在spring配置文件中配置平台事务管理器和平台事务管理模板
第三步 在业务层使用平台事务管理模板实现事务

spring配置文件 tx.xml

<?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:p="http://www.springframework.org/schema/p"
    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">
    <!-- 配置service -->
    <bean id="accountService" class="com.demo.tx.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
    <bean id="accountDao" class="com.demo.tx.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 配置c3p0的连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!-- 配置平台事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置事务管理的模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>
</beans>

数据持久层dao的接口类和实现类
接口类:AccountDao.java

package com.demo.tx;

public interface AccountDao {

    public void transferOutMoney(String from, Double money);
    public void transferInMoney(String to, Double money);
}

实现类:AccountDaoImpl.java----利用spring中的jdbcTemplate

package com.demo.tx;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {


    /* (non-Javadoc)
     * @see com.demo.tx.AccountDao#transferOutMoney(java.lang.String, java.lang.Double)
     */
    public void transferOutMoney(String from, Double money) {
        this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
    }

    /* (non-Javadoc)
     * @see com.demo.tx.AccountDao#transferInMoney(java.lang.String, java.lang.Double)
     */
    public void transferInMoney(String to, Double money) {
        this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
    }

}

业务层的接口和实现类

AccountService.java

package com.demo.tx;

public interface AccountService {

    
    /**
     * @param from 转出
     * @param to 转入
     * @param money 金额
     */
    public void transfer(String from, String to, Double money);
}

AccountServiceImpl.java

package com.demo.tx;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService {

    /* (non-Javadoc)
     * @see com.demo.tx.AccountService#transfer(java.lang.String, java.lang.String, java.lang.Double)
     */
    private AccountDao accountDao;

    /**
     * @param accountDao the accountDao to set
     */
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    // 注入事务管理的模板
    private TransactionTemplate transactionTemplate;

    /**
     * @param transactionTemplate the transactionTemplate to set
     */
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transfer(final String from, final String to, final Double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                accountDao.transferInMoney(to, money);
                accountDao.transferOutMoney(from, money);
            }
        });
        
    }
}

声明式事务管理 —通过配置实现 底层通过aop实现

第一步 在POM文件中引入相关依赖
第二步 在spring的配置文件中配置平台事务管理器
第三步 在spring的配置文件中配置增强

实现声明式事务的两种方式:XML方式和注解方式

实现事务的XML方式

在spring配置文件中增加

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置事务的增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
            <!-- 
            一般find方法不需要事务
            <tx:method name="find" read-only="true"/> -->
        </tx:attributes>
    </tx:advice>
    <!-- aop的配置 -->
    <aop:config>
        <aop:pointcut expression="execution(* com.demo.tx2.AccountServiceImpl.*(..))" id="pointcut1"/>
        <!-- 一个切面一个切点 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
        <!-- 多个切面多个切点 -->
    </aop:config>

修改AccountServiceImpl.java

package com.demo.tx2;
public class AccountServiceImpl implements AccountService {

    /* (non-Javadoc)
     * @see com.demo.tx.AccountService#transfer(java.lang.String, java.lang.String, java.lang.Double)
     */
    private AccountDao accountDao;

    /**
     * @param accountDao the accountDao to set
     */
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String from, String to, Double money) {
        accountDao.transferInMoney(to, money);
//        int i=1/0;
        accountDao.transferOutMoney(from, money);
    }
}
实现事务的注解方式: @Transactional

标注在类前:标示类中所有方法都进行事务处理
标注在接口、实现类的方法前:标示方法进行事务处理
pom.xml文件、数据持久层dao层同编程式事务

在spring 配置文件中增加

   <!-- 配置事务管理器=============================== -->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource"/>
   </bean>
   
   <!-- 开启注解事务================================ -->
   <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

在Service的实现类中增加@Transactional注解,@Transactional可以标注在类前,也可以标注在方法前,里面可以设置隔离级别,事务传播等内容。
标注在类前:标示类中所有方法都进行事务处理
标注在接口、实现类的方法前:标示方法进行事务处理

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)

测试效果:
在AccountServiceImp.java的transfer方法中没有出现异常时,转帐正常。
如果没有事务时,在转出成功之后,转入之前出现异常,则转出成功,转入失败,而我们需要两个操作都失败,加上事务之后,只要发生异常,整个操作就会失败

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值