【SpringFramework】Spring事务

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文简述Spring中数据库及事务相关衍伸知识点。

Spring JDBC 和 Tx

一、准备

(1)新增依赖

<!--新增-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.39</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.39</version>
</dependency>
<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.15</version>
</dependency>

(2)jdbc配置

driverName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/studytest?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username = root
password = 11111

(3)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"
       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">
    <!-- 导入外部配置属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 配置druid数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <property name="driverClassName" value="${driverName}" />
    </bean>
</beans>

(4)数据库

create database studytest;
use studytest;
create table fruitshop
(
    name  varchar(10) null,
    price double      null,
    count int         null,
    total double      null
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、JdbcTemplate

(1)在applicationContext.xml增加JdbcTemplate对象到Spring容器

<!-- 配置JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource" />
    </bean>

(2)测试

public class StudyTest {
    private final static Logger logger = LoggerFactory.getLogger(StudyTest.class);
    @Test
    public void test1() throws SQLException {
        // 老的获取Spring容器方法
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 验证DruidDataSource获取Connection对象
        DruidDataSource dataSource = context.getBean("druidDataSource", DruidDataSource.class);
        DruidPooledConnection connection = dataSource.getConnection();
        logger.info("connection: {}", connection);
        // 验证JdbcTemplate,执行简单的sql
        JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
        String sql = "insert into fruitshop values(?,?,?,?)";
        // int count = jdbcTemplate.update(sql, "波罗", "10", "12", "120");
        sql = "update fruitshop set name=? where name=?";
        int count = jdbcTemplate.update(sql, "pineapple","菠萝");
        logger.info("count: {}", count);
    }
}

(3)使用整合Junit更方便

@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class StudyIntegrateJUnit5Test {
    private static final Logger logger = LoggerFactory.getLogger(StudyIntegrateJUnit5Test.class);
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Test
    public void test01() {
        String sql = "select count(*) from fruitshop";
        Integer fruitCnt = jdbcTemplate.queryForObject(sql, Integer.class);
        logger.info("fruitCnt:{}", fruitCnt);
    }
}

(4)其他CRUD方法

  • 对于增、删、改,均可以使用jdbcTemplate.update(sql, Object...params),该方法返回一个int类型,表示影响的记录数
  • 对于查询:
  • jdbcTemplate.queryForObject(sql, Class):返回单个对象
  • jdbcTemplate.query(sql, BeanPropertyRowMapper<>, params):返回list

事务

(1)什么是事务?

数据库事务(Transaction)是访问数据库并操作各种数据项的一个数据库操作序列,要么全部执行,要么全部不执行,是一个不可分割的单位。
事务由事务开始与事务结束之间执行的全部数据库操作组成。

(2)事务的特性

ACID

  • A:Atomicity,原子性
  • 一个事务中的所有操作,要么全部完成,要么全部不完成,不会卡在中间环节。
  • 事务执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就行事务从未执行过。
  • C:Consistency,一致性
  • 指事务执行前后,数据库都必须处于一致状态。
  • 如果事务成功完成,系统中所有变化将正确应用,系统处于有效状态。
  • 如果事务出现错误,系统中所有变化将自动回滚,系统返回原始状态。
  • I:Isolation,隔离性
  • 指在并发环境中,当不同事务同时操纵相同数据时,每个事务都有各自的完整数据空间。
  • 由并发实物所做的修改,必须与任何其他并发事务所做的修改隔离。
  • 事务查看数据更新时,数据所处的状态要么是另一个事务修改之前状态,要么是另一个事务修改之后状态,不会存在中间状态的数据。
  • D:Durability,持久性
  • 只要事务成功结束,对数据库的更新就必须保存下来。
  • 即使系统发生崩溃,重启数据库后还是能恢复到事务成功结束时的状态。

(3)编程式事务

即事务功能全部由自己编写代码来实现

// 一个演示手写事务实现的方法
public void demo() {
    Connection conn = dataSource.getConnection();
    try {
        // 开启事务:关闭事务自动提交
        conn.setAutoCommit(false);
        // 核心代码
        // 提交事务
        conn.commit();
    }
    catch(Exception e) {
        // 发生异常,回滚事务
        conn.rollback();
    }
    finally{
        // 最终释放连接
        conn.close();
    }
}

编程式事务的缺陷:

  • 细节没有被屏蔽:具体操作过程中,所有细节都要程序员自己完成,比较繁琐;
  • 代码复用性不高:如果没有有效抽取出来,每次实现功能都要自己编写代码,代码没有复用。

(4)声明式事务

通过上述编程式事务的demo,我们可想到——事务控制的代码是有规律的——代码结构基本固定,所以框架就可以将固定的代码抽取出来,进行封装。

封装完成后,我们只需要简单配置就可完成开启事务的全部操作。

好处:

  • 提高开发效率
  • 消除冗余代码
  • 框架通过广泛应用,可以综合考虑相关领域中在实际开发环境下可能遇到的问题,能针对性的对健壮性、性能等各方面进行优化

因此:

  • 编程式事务:自己写代码实现事务
  • 声明式事务:通过框架配置实现事务

Spring中基于注解实现声明式事务

创建数据库、表:

CREATE DATABASE `spring`;
use `spring`;
CREATE TABLE `t_emp` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `name` varchar(20) DEFAULT NULL COMMENT '姓名',
   `age` int(11) DEFAULT NULL COMMENT '年龄',
   `sex` varchar(2) DEFAULT NULL COMMENT '性别',
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `t_book` (
    `book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `book_name` varchar(20) DEFAULT NULL COMMENT '图书名称',
    `price` int(11) DEFAULT NULL COMMENT '价格',
    `stock` int(10) unsigned DEFAULT NULL COMMENT '库存(无符号)',
    PRIMARY KEY (`book_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert  into `t_book`(`book_id`,`book_name`,`price`,`stock`) values (1,'斗破苍穹',80,100),(2,'斗罗大陆',50,100);
CREATE TABLE `t_user` (
    `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `username` varchar(20) DEFAULT NULL COMMENT '用户名',
    `balance` int(10) unsigned DEFAULT NULL COMMENT '余额(无符号)',
    PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
insert  into `t_user`(`user_id`,`username`,`balance`) values (1,'admin',50);

(1)没有添加事务的情况

@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class TestBookSellNoTranstion {
    @Autowired
    private BookController bookController;
    @Test
    public void testBuyBook(){
        /*
        * 用户购买图书,先查询图书的价格,再更新图书的库存和用户的余额
        * 假设用户id为1的用户,购买id为1的图书,操作顺序如下:
        * 1. 从书籍库存中减1,原来100本,减后为99本;
        * 2. 再从用户账户扣除购书款80,用户余额为50,而图书价格为80,购买图书之后,用户的余额为-30
        * 数据库中余额字段设置了无符号,因此无法将-30插入到余额字段;此时执行sql语句会抛出SQLException
        * */
        bookController.buyBook(1,1);
       /* 观察结果;
       因为没有添加事务,图书的库存更新了,但是用户余额因为异常而未更新
       这个结果不是我们想要的,购买图书是一个完整的过程,书本拿走,账户扣款;而此时因为账户钱不够,而导致用户为花钱就买走的图书。
       */
    }
}

(2)添加事务的情况

  1. Spring配置文件中引入tx命名空间
<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"
       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">
    <!-- 扫描组件 -->
    <context:component-scan base-package="com.sheeprunner.springjdbc" />
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="druidDataSource"></property>
    </bean>
    <!--
    开启事务的注解驱动
    通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
    -->
    <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

由于开启了事务注解驱动(在Spring配置文件中),并且在service(一般在业务层)使用了事务注解,
此时账户扣款发生异常,两个表都没有更新

@Transactional注解标识的位置:

  • @Transactional标识在方法上,则只会影响该方法
  • @Transactional标识的类上,则会影响类中所有的方法

(3)事务属性

1、只读

针对一个查询操作,如果我们把事务设置为只读,就明确告诉数据库,不涉及写操作,这样数据库可以针对查询进行优化。

import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)

注意,该属性只能对查询的方法配置,如果对增删改配置,会抛出下面异常:

Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

2、超时

事务在执行过程中,可能遇到某些问题,导致程序卡住,从而长时间占用数据库资源,大概率是程序运行出现问题(如应用或数据库网络连接异常等)。
此时在阻塞资源的程序应该被回滚,撤销已做操作,结束事务,把资源让出来,让其他程序先执行。

// 超时单位为秒
import org.springframework.transaction.annotation.Transactional;
@Transactional(timeout = 3)
public void buyBook(Integer bookId, Integer userId) {
        // 睡眠4秒
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 查询图书价格
        Integer price = bookDao.getPriceByBookId(bookId);
        // 更新图书库存
        bookDao.updateStock(bookId);
        // 更新用户余额
        bookDao.updateBalance(userId, price);
        }

执行过程中如果超时,则抛出异常:

org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Sun Dec 15 21:57:34 CST 2024

3、回滚策略

声明式事务默认只针对运行时异常回滚,编译时异常不回滚。

@Transactional四个属性控制回滚方式:

  1. rollbackFor:设置一个Class类型对象,表示出现什么异常类型需要回滚
  2. rollbackForClassName:设置一个字符串类型的全类名
  3. noRollbackFor:设置一个Class类型对象,表示出现什么异常类型不需要回滚
  4. noRollbackForClassName:设置一个字符串类型的全类名
@Transactional(noRollbackFor = ArithmeticException.class )

上述设置表示,即使出现数学运算异常(ArithmeticException),也不发生回滚。

4、隔离级别

数据库系统必须具有隔离并发运行各个事务的能力,使各事务间不互相影响 ,避免并发问题。
一个事务与其他事务的隔离程度称为隔离级别。
以下是sql标准规定的四种隔离级别,隔离级别递增,总之,隔离性越高,数据一致性越好,并发性越弱。

  1. 读未提交:READ UNCOMMITTED,允许事务1读取事务2的未提交修改。
  2. 读已提交:READ COMMITTED,事务1只能读取事务2已提交的修改。
  3. 可重复度:REPEATABLE READ,确保事务1可以多次从一个字段中读取到相同值,即事务1执行期间禁止其他事务对该字段进行更新。
  4. 串行化:SERIALIZABLE,确保事务1可以多次从一个表中读取到相同的行,在事务1执行期间,禁止其他事务对表进行增删改。避免任何并发问题,但性能十分低下。

各个隔离级别解决并发问题的能力见下表:

隔离级别

脏读

不可重复读

幻读

READ UNCOMMITTED

READ COMMITTED

REPEATABLE READ

SERIALIZABLE

各种数据库产品对事务隔离级别的支持程度:

隔离级别

Oracle

MySQL

READ UNCOMMITTED

×

READ COMMITTED

√(默认)

REPEATABLE READ

×

√(默认)

SERIALIZABLE

使用方式

@Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交
@Transactional(isolation = Isolation.READ_COMMITTED)//读已提交
@Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读
@Transactional(isolation = Isolation.SERIALIZABLE)//串行化

5、传播行为

有两个方法A和B,都存在事务,当A执行过程中调用B,事务是如果传递的,就是传播行为。

有7种传播行为:

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

属性名称propagation

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
    private final int value;
    private Propagation(int value) {
        this.value = value;
    }
    public int value() {
        return this.value;
    }
}

以最常用的REQUIRES和REQUIRES_NEW为例:

  • 当两个都是默认当前事务(REQUIRES)时,循环中第一次执行成功,第二次执行失败,则两次都回滚;
  • 当两个都是REQUIRES_NEW(开启新事务),则第一次成功的会更新到数据库,第二次失败的回滚。

(4) 全注解开发

1、配置类

package com.sheeprunner.springjdbc.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;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * @description:
 * @author: RunningSheep
 * @date: 2024-12-15 23:09
 * @version: V1.0
 */
@Configuration
@ComponentScan("com.sheeprunner.springjdbc")
// 启用事务
@EnableTransactionManagement
public class SpringTxConfig {
    @Bean
    public DataSource getDataSource() throws IOException {
        InputStream resourceAsStream = SpringTxConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(properties.getProperty("driverName"));
        dataSource.setUrl(properties.getProperty("url"));
        dataSource.setUsername(properties.getProperty("username"));
        dataSource.setPassword(properties.getProperty("password"));
        return dataSource;
    }
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    @Bean
    public DataSourceTransactionManager getDatasourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dstm = new DataSourceTransactionManager();
        dstm.setDataSource(dataSource);
        return dstm;
    }
}

2、测试

@Test
    public void test() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringTxConfig.class);
        BookController bookController = context.getBean("bookController", BookController.class);
        bookController.chekout(new Integer[]{1,2}, 1);
    }

(5)全XML配置

<!--
    开启事务的注解驱动
    通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
    -->
    <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
    <!--<tx:annotation-driven transaction-manager="transactionManager" />-->
    <!--下面为使用XML方式配置事务-->
    <aop:config>
        <!-- 配置事务通知和切入点表达式 -->
        <aop:advisor advice-ref="txAdvice"
                     pointcut="execution(* com.sheeprunner.springjdbc.service.*.*(..))" />
    </aop:config>
    <!-- tx:advice标签:配置事务通知 -->
    <!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
    <!-- transaction-manager属性:关联事务管理器 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- tx:method标签:配置具体的事务方法 -->
            <!-- name属性:指定方法名,可以使用星号代表多个字符 -->
            <tx:method name="get*" read-only="true"/>
            <tx:method name="query*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <!-- read-only属性:设置只读属性 -->
            <!-- rollback-for属性:设置回滚的异常 -->
            <!-- no-rollback-for属性:设置不回滚的异常 -->
            <!-- isolation属性:设置事务的隔离级别 -->
            <!-- timeout属性:设置事务的超时属性 -->
            <!-- propagation属性:设置事务的传播行为 -->
            <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
            <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
            <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        </tx:attributes>
    </tx:advice>
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
17天前
|
XML Java 数据格式
【SpringFramework】Spring初体验
Spring是一款由Rod Johnson创立的主流Java EE轻量级开源框架,它旨在简化Java企业级项目开发,提供一站式轻量级解决方案,取代复杂的EJB。Spring的核心功能包括IoC(控制反转)和AOP(面向切面编程),并支持非侵入式开发、组件化和容器管理。这篇文章简要描述相关知识点和初始springframework。
105 60
【SpringFramework】Spring初体验
|
9天前
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
98 69
|
7天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
40 21
|
2天前
|
Java 测试技术 Spring
【SpringFramework】Spring整合JUnit
本文简述Spring整合JUnit单元测试组件的通用方法,可以简化Spring框架测试。
31 14
|
9天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
38 13
|
1月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
48 2
Spring高手之路26——全方位掌握事务监听器
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
2月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
63 1
Spring高手之路24——事务类型及传播行为实战指南
|
2月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
2月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
76 3

热门文章

最新文章