Spring的事务

本文详细介绍了Spring中的事务控制,包括编程式事务管理和声明式事务管理。编程式事务管理通过PlatformTransactionManager接口进行事务操作,如开始、提交和回滚事务。声明式事务管理则通过XML或注解配置实现,简化了事务处理。重点讲解了基于XML和注解的声明式事务控制,包括事务隔离级别、传播行为和事务状态。同时,提供了事务注解@Transactional的使用示例。

1. Spring中的事务控制方式

Spring的事务控制可以分为编程式事务控制和声明式事务控制.
 
编程式
 
开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用。
 
声明式
 
开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。
 

2. 编程式事务控制相关对象【了解】

2.1 PlatformTransactionManager

PlatformTransactionManager接口,是spring的事务管理器,里面提供了我们常用的操作事务的方法。

方法

说明

TransactionStatus getTransaction(TransactionDefinition definition);

获取事务的状态信息

void commit(TransactionStatus status)

提交事务

void rollback(TransactionStatus status)

回滚事务

注意:

  • PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。

 

  • Dao层技术是jdbcTemplatemybatis时: DataSourceTransactionManager

 

  • Dao层技术是hibernate时:

HibernateTransactionManager

 

  • Dao层技术是JPA时:

JpaTransactionManager

2.2 TransactionDefinition

TransactionDefinition接口提供事务的定义信息(事务隔离级别、事务传播行为等等)

方法

说明

int getIsolationLevel()

获得事务的隔离级别

int getPropogationBehavior()

获得事务的传播行为

int getTimeout()

获得超时时间

boolean isReadOnly()

是否只读

(1)事务隔离级别

设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。

(2)事务传播行为

事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制。

参数

说明

 

REQUIRED

如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)

SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)

MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常

REQUERS_NEW

新建事务,如果当前在事务中,把当前事务挂起

NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

NEVER

以非事务方式运行,如果当前存在事务,抛出异常

 

NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行

REQUIRED 类似的操作

  • read-only(是否只读):建议查询时设置为只读

 

  • timeout(超时时间):默认值是-1,没有超时限制。如果有,以秒为单位进行设置

2.3 TransactionStatus

TransactionStatus 接口提供的是事务具体的运行状态。

方法

说明

boolean isNewTransaction()

是否是新事务

boolean hasSavepoint()

是否是回滚点

boolean isRollbackOnly()

事务是否回滚

boolean isCompleted()

事务是否完成

可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事  务状态。

2.4 代码实现

(1)配置文件

(2)业务层代码

@Service
public class AccountServiceImpl implements AccountService { @Autowired
private AccountDao accountDao;

@Autowired
private PlatformTransactionManager transactionManager;

@Override
public void transfer(String outUser, String inUser, Double money) {
// 创建事务定义对象
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置是否只读,false支持事务
def.setReadOnly(false);
// 设置事务隔离级别,可重复读mysql默认级别
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
// 设置事务传播行为,必须有事务
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 配置事务管理器
TransactionStatus status = transactionManager.getTransaction(def);

try {
// 转账
accountDao.out(outUser, money); accountDao.in(inUser, money);

// 提交事务
transactionManager.commit(status);
} catch (Exception e) { e.printStackTrace();
// 回滚事务
transactionManager.rollback(status);
}
}
}

2.5 知识小结

Spring中的事务控制主要就是通过这三个API实现的。

  • PlatformTransactionManager 负责事务的管理,它是个接口,其子类负责具体工作

 

  • TransactionDefinition 定义了事务的一些相关参数

 

  • TransactionStatus 代表事务运行的一个实时状态

理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。

3. 基于XML的声明式事务控制【重点】

Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的。

声明式事务控制明确事项:

  • 核心业务代码(目标对象) (切入点是谁?)
  • 事务增强代码(Spring已提供事务管理器))(通知是谁?) 切面配置(切面如何配置?)

3.1 快速入门

需求

使用spring声明式事务控制转账业务。

步骤分析

  1. 引入tx命名空间

 

  1. 事务管理器通知配置

 

  1. 事务管理器AOP配置

 

  1. 测试事务控制转账业务代码

(1)引入tx命名空间

<?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
">
</beans>

(2)事务管理器通知配置

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

    <!--事务的注解支持-->
  <!--  <tx:annotation-driven/>-->

    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--定义事务的一些属性 * 表示当前任意名称的方法都走默认配置-->
        <!--
            name: 切点方法名称
            isolation:事务的隔离级别
            propagation:事务的传播行为
            read-only:是否只读
            timeout:超时时间
        -->
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/>
            <!--**CRUD常用配置**	-->
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*"/>

        </tx:attributes>
    </tx:advice>

(3)事务管理器AOP配置

 <!--aop配置:配置切面-->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
    </aop:config>

(4)测试事务控制转账业务代码

package com.lagou.test;

import com.lagou.config.SpringConfig;
import com.lagou.servlet.AccountSerivce;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration({"classpath:applicationContext.xml"})
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceImplTest {

    @Autowired
    private AccountSerivce accountSerivce;

    @Test
    public void testTransfer(){
        accountSerivce.transfer("tom","jerry",100d);
    }


}

3.2 事务参数的配置详解

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>

 

  • name:切点方法名称

 

  • isolation:事务的隔离级别

 

  • propogation:事务的传播行为

 

  • timeout:超时时间

 

  • read-only:是否只读

CRUD常用配置

<tx:attributes>

<tx:method name="save*" propagation="REQUIRED"/>

<tx:method name="delete*" propagation="REQUIRED"/>

<tx:method name="update*" propagation="REQUIRED"/>

<tx:method name="find*" read-only="true"/>

<tx:method name="*"/>

</tx:attributes>

3.3 知识小结

  • 平台事务管理器配置

 

  • 事务通知的配置

 

  • 事务aop织入的配置

4. 基于注解的声明式事务控制【重点】

4.1 常用注解

步骤分析

  1. 修改service层,增加事务注解
  2. 修改spring核心配置文件,开启事务注解支持

(1)修改service层,增加事务注解

package com.lagou.servlet.impl;

import com.lagou.dao.AccountDao;
import com.lagou.servlet.AccountSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class AccountServiceImpl implements AccountSerivce {

    @Autowired
    private AccountDao accountDao;


    //@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = -1,readOnly = false)
    public void transfer(String outUser, String inUser, Double money) {

        //调用dao的out及in方法
        accountDao.out(outUser,money);

        int i = 1/0;

        accountDao.in(inUser,money);
    }
}

(2)修改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: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
">

   <!-- IOC注解扫描-->
    <context:component-scan base-package="com.lagou"></context:component-scan>


    <!--引入properties-->
   <!-- <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>-->


    <!--dataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>


    <!--jdbcTemplate-->
<!--    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"/>
    </bean>-->



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

    <!--事务的注解支持-->
  <tx:annotation-driven/>

    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--定义事务的一些属性 * 表示当前任意名称的方法都走默认配置-->
        <!--
            name: 切点方法名称
            isolation:事务的隔离级别
            propagation:事务的传播行为
            read-only:是否只读
            timeout:超时时间
        -->
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/>
            <!--**CRUD常用配置**	-->
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*"/>

        </tx:attributes>
    </tx:advice>


    <!--aop配置:配置切面-->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>
    </aop:config>






</beans>

4.2 纯注解

核心配置类

package com.lagou.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration  // 声明该类为核心配置类
@ComponentScan("com.lagou")  // 包扫描
@Import(DataSourceConfig.class) //导入其他配置类
@EnableTransactionManagement //事务的注解驱动
public class SpringConfig {

    @Bean
    public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public PlatformTransactionManager getPlatformTransactionManager(@Autowired DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        return dataSourceTransactionManager;
    }


}
package com.lagou.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

@PropertySource("classpath:jdbc.properties") //引入properties文件
public class DataSourceConfig {

    @Value("${jdbc.driverClassName}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;



    @Bean //会把当前方法的返回值对象放进IOC容器中
    public DataSource getDataSource(){

        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }



}

4.3 知识小结

  • 平台事务管理器配置(xml、注解方式)

 

  • 事务通知的配置(@Transactional注解配置)

 

  • 事务注解驱动的配置 <tx:annotation-driven/>@EnableTransactionManagement

 

节选自拉钩教育JAVA系列课程

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

### 三级标题:Spring 事务管理概述 Spring 事务管理是一种用于管理数据库事务的机制,它允许开发者通过声明式或编程式的方式来控制事务的边界。声明式事务管理是通过 AOP(面向切面编程)实现的,它允许开发者通过配置文件或注解来定义事务规则,而无需在业务逻辑代码中显式地编写事务管理代码[^2]。 ### 三级标题:Spring 事务管理的使用 在 Spring 中,声明式事务管理可以通过 XML 配置文件或注解来实现。使用注解方式更为简洁,特别是在 Spring Boot 项目中。通过 `@Transactional` 注解,可以轻松地在服务层方法上声明事务边界。例如: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Transactional public User save(User user) { // 业务逻辑... return userDAO.save(user); } } ``` 此外,Spring 还支持分布式事务管理,可以通过集成 Seata 实现全局事务管理。例如: ```java @GlobalTransactional // 分布式事务注解 public void createOrder(Order order) { orderService.create(order); // 订单库操作 inventoryService.decreaseStock(); // 库存库操作 } ``` ### 三级标题:Spring 事务管理的常见问题及解决方案 在使用 Spring 事务管理时,可能会遇到一些常见问题,如事务不生效、超时和死锁等。为了解决这些问题,需要根据业务需求和性能要求选择合适的事务传播行为和隔离级别。同时,还需要注意事务的传播行为和隔离级别的配置是否正确,以及数据库是否支持事务[^1]。 ### 三级标题:Spring 事务管理的调试与监控 为了确保事务管理的正确性和性能,开启调试日志是非常关键的。通过日志可以监控事务的执行情况,及时发现并解决问题。例如,在 Spring Boot 应用中,可以在 `application.properties` 文件中设置日志级别: ```properties logging.level.org.springframework.transaction=DEBUG ``` ### 三级标题:Spring 事务管理的扩展 除了基本的事务管理功能之外,Spring 还提供了与 Hibernate 整合的事务管理方法,以及与其他框架如 MyBatis 的集成。此外,还可以通过 Spring Data JPA 来简化数据访问层的事务管理[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值