详解事务:Mysql事务、Spring事务、分布式事务

news2025/6/9 19:46:27

详解事务:Mysql事务、Spring事务、分布式事务

  • (一)Mysql事务
    • 【1】4种隔离级别
    • 【2】测试案例
  • (二)Spring事务
    • 【1】准备测试代码
      • (1)添加依赖
      • (2)配置文件
      • (3)添加代码Controller、Service
      • (4)测试路径
      • (5)查看日志
    • 【2】隔离性
    • 【3】传播性
      • (1)什么是事务的传播性
      • (2)传播性的7种种类
      • (3)Required(内部方法和外部方法共用同一个事务)
      • (4)Requires_NEW(外部方法和内部方法各自有自己独立的事务)
          • 案例一:transfer方法是REQUIRED,update方法是Requires_NEW,两个方法都没有异常
          • 案例二:transfer方法是REQUIRED,没有异常;update方法是Requires_NEW,有异常(要看内部方法update的异常有没有被处理)
          • 案例三:transfer方法是REQUIRED,有异常;update方法是Requires_NEW,没有异常
      • (5)NESTED(外部方法为主事务,内部方法为子事务,事务嵌套)
          • 案例一:transfer方法有异常并回滚,update方法没有异常但是也会回滚
          • 案例二:transfer方法没有异常,update方法有异常,子事务回滚不影响主事务
      • (6)MANDATORY(强制性)
      • (7)SUPPORTS
      • (8)NOT_SUPPORTED(有事务就挂起)
      • (9)NEVER(禁止添加事务)
    • 【4】回滚规则
    • 【5】是否只读
    • 【6】超时时间
    • 【7】事务失效的场景和原因
        • (1)事务注解只有加在public方法上才会有效
        • (2)自调用会造成事务失效
        • (3)
  • (三)分布式事务

(一)Mysql事务

【1】4种隔离级别

(1)序列化
同一时间只能有一个事务执行,所有事务串行执行
(2)可重复读
InnoDB引擎默认的隔离级别,当前事务的变化不会被外部看到
(3)提交读
当前事务可以看到其他事务对数据的修改
(4)未提交读

【2】测试案例

(1)查看全局的隔离级别和查看当前会话的隔离级别(mysql5.7版本的命令)
在这里插入图片描述(2)修改当前会话的隔离级别
在这里插入图片描述(3)测试序列化
先执行会话1的这前两行代码,但是不执行提交事务
在这里插入图片描述然后执行会话2的这前两行代码,也不执行提交事务
在这里插入图片描述会发现事务2的事务开启不了,必须要等前一个事务提交完
在这里插入图片描述执行完会话1的commit后,会话2就能开启事务

安全性最高,但是效率不好

(4)测试可重复读
修改当前会话的隔离级别
在这里插入图片描述然后会话1开启事务,并且查询值,但是不提交事务。此时查询的money结果是99
在这里插入图片描述然后会话2开启事务,并且修改值(此时两个事务可以同时进行了),将money值修改为100。但是不提交事务
在这里插入图片描述
再回到会话1,执行查询语句,money结果还是99
在这里插入图片描述会话1的事务提交完后,重新执行查询,money结果才是100(此时会话2的事务还没有提交)

也就是说,在当前事务中查询的结果不变,即使这个数据已经被其他事务修改过了,当前事务对其他事务的修改是不可见的

(5)可重复读造成的幻读
会话2事务提交成功了,但是因为事务未提交前不可见,所以会话1读到的值跟最终的实际值还是可能不一样。

(6)测试提交读(不可重复读)
会话1的事务提交完后,必须等到会话2的事务也提交完,才能查到会话2修改的值。即使会话2把money改成100了,只要会话2还没有提交事务,会话1读到的就一直是99。

这种隔离级别也可能会出现幻读。

可重复读造成幻读的原因就是会话2事务提交成功,导致会话1读到的值跟最终的实际值不一样。而不可重复读造成的幻读的原因就是会话2修改值后还没有提交事务,会话1就可以读到修改后的值100了,但是如果会话2回滚了呢,最终的真实结果应该还是99。但是会话1已经获取100并使用了

例如两个会话开启事务后,都先执行select语句,都发现没有这个数据,然后都执行一个insert方法插入数据,执行insert就会加锁,那第二个事务进来就会被锁住。

(7)未提交读

(二)Spring事务

【1】准备测试代码

(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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.allen</groupId>
    <artifactId>transactional</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>transactional</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>

        <!--<dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

(2)配置文件

server.port=8081

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

logging.level.root=debug

(3)添加代码Controller、Service

package com.allen.transactional.Con;

import com.allen.transactional.Service.UserService01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: TestController
 * @Author: AllenSun
 * @Date: 2022/12/20 下午10:37
 */
@RestController
public class TestController {

    @Autowired
    UserService01 userService01;

    @GetMapping("/hello")
    public void hello () {
        userService01.transfer();
    }
}
package com.allen.transactional.Service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @ClassName: UserService01
 * @Author: AllenSun
 * @Date: 2022/12/20 下午10:38
 */
@Service
public class UserService01 {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    UserService02 userService02;

    @Transactional
    public void transfer() {
        jdbcTemplate.update("update order_1 set count = ? where user_id=?;",1,101);
        int i=1/0;
    }
}
package com.allen.transactional.Service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

/**
 * @ClassName: UserService01
 * @Author: AllenSun
 * @Date: 2022/12/20 下午10:38
 */
@Service
public class UserService02 {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public void update() {
        jdbcTemplate.update("update order_1 set count = ? where user_id=?;",100,103);
    }

}

(4)测试路径

http://127.0.0.1:8081/hello

(5)查看日志

注意的是在transfer方法中添加了一行int i=1/0;导致抛出异常,触发事务,可以看看日志的详细内容

【2】隔离性

【3】传播性

(1)什么是事务的传播性

事务传播行为是为了解决业务层方法之间互相调用的事务问题,当一个事务方法被另一个事务方法调用时,事务该以何种状态存在?例如新方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,等等,这些规则就涉及到事务的传播性。

(2)传播性的7种种类

默认是Required。

用的比较多的就是REQUIRED、REQUIRES_NEW、NESTED这三种,90%的情况下使用REQUIRED就可以解决了
在这里插入图片描述

(3)Required(内部方法和外部方法共用同一个事务)

@Transactional注解的默认属性就是REQUIRED
方法和它的内部方法共用同一个事务
(1)如果transfer方法已经开启事务了,那么update方法就不会再开启新的事务,而是加到transfer方法的事务中来
(2)如果transfer方法没有开启事务,那么update才会开启自己的新的事务
(3)如果transfer方法抛出异常也会造成update方法的回滚

在这里插入图片描述
测试前的数据
在这里插入图片描述
测试后的数据没有变化

查看控制台的日志内容

# 创建transfer方法的事务
o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
# 执行tranfer方法的sql
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows

# 将update方法添加到transfer方法的事务中去
o.s.j.d.DataSourceTransactionManager     : Participating in existing transaction
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows

# 抛出异常,开始回滚
o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@79ede17d]]]
o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection 

因为是把update方法加入到transfer方法的事务中去的,所以两个方法共用一个事务,如果发生回滚的话,两个方法是都要回滚的

(4)Requires_NEW(外部方法和内部方法各自有自己独立的事务)

(1)如果外部有事务,内部也会开启自己的事务,会将外部的事务挂起,内部的事务独自运行。可能会同时存在两个事务
1-transfer方法抛出异常后会回滚,但是update方法不会跟着回滚,因为update方法开启的是自己的事务
2-如果transfer方法正常执行,而update方法抛出异常回滚,那就要看update方法的异常是否会处理掉,如果update的异常被处理了,transfer方法就不会回滚,否则受到update的异常影响也会回滚
(2)如果外部没有事务,内部还是会开启自己的事务

案例一:transfer方法是REQUIRED,update方法是Requires_NEW,两个方法都没有异常

在这里插入图片描述这里有个细节,如果对user_id字段没有加数据库索引,在执行的时候,transfer方法会对表加表锁,那么update方法执行sql的时候就会陷入死锁的情况,访问超时。所以可以给user_id字段加上唯一索引,这样transfer方法就只会加行锁,就不会出现死锁的问题了

查看控制台日志

# 创建transfer方法的事务
2022-12-21 00:01:31.146 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]] for JDBC transaction
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]] to manual commit
# 准备执行transfer方法的sql
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:01:31.147 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:01:31.149 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows

# 挂起transfer方法的事务,创建update方法的事务
2022-12-21 00:01:31.149 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:01:31.150 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] for JDBC transaction
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] to manual commit
# 准备执行update方法的事务
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:01:31.151 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows

# 提交update方法的事务
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Initiating transaction commit
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]]
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@201ca654]]] after transaction
2022-12-21 00:01:31.152 DEBUG 65541 --- [nio-8081-exec-2] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource

# 唤醒transfer方法的事务,然后提交
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Resuming suspended transaction after completion of inner transaction
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Initiating transaction commit
2022-12-21 00:01:31.153 DEBUG 65541 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5f489349]]]

查看方法执行的结果,两个方法的sql都执行成功了
在这里插入图片描述

案例二:transfer方法是REQUIRED,没有异常;update方法是Requires_NEW,有异常(要看内部方法update的异常有没有被处理)

是因为内部的update方法抛出异常后没有进行处理,导致外部的方法也会出现异常,导致两个方法都会回滚
在这里插入图片描述查看控制台日志

# 创建transfer方法的事务
2022-12-21 00:11:17.147 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:11:17.153 DEBUG 67348 --- [nio-8081-exec-2] o.a.tomcat.jdbc.pool.PooledConnection    : Instantiating driver using class: com.mysql.jdbc.Driver [url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8]
2022-12-21 00:11:17.414 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] for JDBC transaction
2022-12-21 00:11:17.416 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:11:17.421 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:11:17.421 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:11:17.433 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 挂起transfer方法的事务,并且创建update方法的事务
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] for JDBC transaction
2022-12-21 00:11:17.435 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] to manual commit
# 执行update方法的sql
2022-12-21 00:11:17.437 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:11:17.437 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:11:17.438 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 发现异常,准备回滚update方法
2022-12-21 00:11:17.439 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
2022-12-21 00:11:17.439 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]]
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6e1ad23e]]] after transaction
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource

# 唤醒transfer方法的事务
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Resuming suspended transaction after completion of inner transaction
# transfer方法也开始回滚
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
2022-12-21 00:11:17.440 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]]
2022-12-21 00:11:17.442 DEBUG 67348 --- [nio-8081-exec-2] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@771338ee]]] after transaction

两个方法都发生了回滚,接下来对内部update方法的异常进行处理然后再看update的方法对transfer方法有没有影响
在这里插入图片描述再来看看控制台日志

# 创建transfer方法的事务
2022-12-21 00:22:55.704 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:22:55.710 DEBUG 68808 --- [nio-8081-exec-1] o.a.tomcat.jdbc.pool.PooledConnection    : Instantiating driver using class: com.mysql.jdbc.Driver [url=jdbc:mysql://127.0.0.1:3306/sharding-jdbc-order?characterEncoding=UTF-8]
2022-12-21 00:22:55.955 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] for JDBC transaction
2022-12-21 00:22:55.956 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:22:55.959 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:22:55.959 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:22:55.973 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 挂起transfer方法的事务,并且创建update方法的事务
2022-12-21 00:22:55.974 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:22:55.975 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] for JDBC transaction
2022-12-21 00:22:55.975 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] to manual commit
# 执行update方法的sql
2022-12-21 00:22:55.977 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:22:55.977 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# update方法出现异常,开始回滚update的sql
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
2022-12-21 00:22:55.979 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]]
2022-12-21 00:22:55.981 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@6b1e08a1]]] after transaction
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Resuming suspended transaction after completion of inner transaction
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction commit
# 提交transfer方法的事务
2022-12-21 00:22:55.982 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]]
2022-12-21 00:22:55.983 DEBUG 68808 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@559824e7]]] after transaction

查看结果,可以看到transfer方法修改成功了,update方法没有修改成功
在这里插入图片描述

案例三:transfer方法是REQUIRED,有异常;update方法是Requires_NEW,没有异常

在这里插入图片描述查看控制台日志信息

# 创建transfer方法的事务
2022-12-21 00:31:25.591 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:31:25.833 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] for JDBC transaction
2022-12-21 00:31:25.835 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:31:25.839 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:31:25.839 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:31:25.852 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 挂起transfer方法的事务,创建update方法的事务
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Suspending current transaction, creating new transaction with name [com.allen.transactional.Service.UserService02.update]
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] for JDBC transaction
2022-12-21 00:31:25.854 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] to manual commit
# 执行update方法的sql
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:31:25.856 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 提交update方法的事务
2022-12-21 00:31:25.857 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction commit
2022-12-21 00:31:25.857 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]]
2022-12-21 00:31:25.858 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@7f5ec022]]] after transaction
2022-12-21 00:31:25.858 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource
# 唤醒transfer方法的事务
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Resuming suspended transaction after completion of inner transaction
# transfer方法出现异常,开始回滚transfer方法的sql
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
2022-12-21 00:31:25.859 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]]
2022-12-21 00:31:25.861 DEBUG 69835 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@17ce73b0]]] after transaction
2022-12-21 00:31:25.861 DEBUG 69835 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource

查看数据库结果,transfer方法回滚了,没有修改成功,而update方法事务成功提交了,修改成功
在这里插入图片描述

(5)NESTED(外部方法为主事务,内部方法为子事务,事务嵌套)

如果主事务发生了回滚,子事务也会跟着回滚

案例一:transfer方法有异常并回滚,update方法没有异常但是也会回滚

在这里插入图片描述

# 创建transfer方法的事务
2022-12-21 00:43:43.676 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2022-12-21 00:43:43.915 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]] to manual commit
# 执行transfer方法的sql
2022-12-21 00:43:43.920 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:43:43.921 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:43:43.937 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 创建嵌套子事务update方法的事务
2022-12-21 00:43:43.938 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating nested transaction with name [com.allen.transactional.Service.UserService02.update]
# 执行update方法的sql
2022-12-21 00:43:43.943 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:43:43.943 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:43:43.944 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing transaction savepoint
# transfer方法出现异常,开始回滚,主事务和子事务都会回滚,两个事务都没有提交
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
2022-12-21 00:43:43.945 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]]
2022-12-21 00:43:43.946 DEBUG 71230 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@5e363a1d]]] after transaction
2022-12-21 00:43:43.946 DEBUG 71230 --- [nio-8081-exec-1] o.s.jdbc.datasource.DataSourceUtils      : Returning JDBC Connection to DataSource

两个方法都没有修改数据库,数据库的数据不变

案例二:transfer方法没有异常,update方法有异常,子事务回滚不影响主事务

给update方法加上异常处理,否则主事务也还是会回滚
在这里插入图片描述

# 创建transfer方法的事务
2022-12-21 00:53:26.042 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.allen.transactional.Service.UserService01.transfer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
# 执行transfer方法的sql
2022-12-21 00:53:26.317 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:53:26.318 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:53:26.332 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# 创建内部方法update的子事务
2022-12-21 00:53:26.334 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Creating nested transaction with name [com.allen.transactional.Service.UserService02.update]
# 执行update方法的sql
2022-12-21 00:53:26.339 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL update
2022-12-21 00:53:26.339 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [update order_1 set count = ? where user_id=?;]
2022-12-21 00:53:26.340 DEBUG 72498 --- [nio-8081-exec-1] o.s.jdbc.core.JdbcTemplate               : SQL update affected 1 rows
# update方法出现异常,开始回滚
2022-12-21 00:53:26.341 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Rolling back transaction to savepoint
# 提交transfer方法的事务
2022-12-21 00:53:26.342 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Initiating transaction commit
2022-12-21 00:53:26.342 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection@57a99f1]]]
2022-12-21 00:53:26.344 DEBUG 72498 --- [nio-8081-exec-1] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection 

在这里插入图片描述

(6)MANDATORY(强制性)

MANDATORY的方法事务不能独立存在,必须加到一个事务中去
(1)如果transfer方法有事务,那么update方法就加入到transfer方法的事务中去
(2)如果transfer方法没有事务,那么update方法的事务就会报错
在这里插入图片描述

(7)SUPPORTS

(1)如果transfer方法有事务,那么update方法就加入到transfer方法的事务中去
(2)如果transfer方法没有事务,那么update方法的事务加了也没用,直接用非事务的方式继续运行

(8)NOT_SUPPORTED(有事务就挂起)

加了这个属性以后,如果当前方法加了事务,就把事务挂起,以非事务的方式运行

(9)NEVER(禁止添加事务)

加了这个属性以后,如果当前方法加了事务,就会直接抛出异常,必须以非事务的方式运行

【4】回滚规则

什么情况下才会回滚?
只有在遇到运行时异常RuntimeException 的时候才会回滚,如果遇到的是检查性异常,就不会触发回滚

(1)添加一个IOException,那么就不会触发回滚,因为不是运行时异常
在这里插入图片描述
(2)添加rollbackfor参数,修改回滚的规则,指定哪种异常会回滚
这个时候就可以触发回滚了
在这里插入图片描述
(3)也可以用noRollbackFor参数,指定哪种异常不回滚

【5】是否只读

如果一个业务方法只有一个查询sql,那就没有必要添加事务了,添加事务反而会导致执行的效率变慢。

但是如果一个业务方法中有多个查询sql,默认情况下,每个查询sql都会开启一个独立的事务,这个时候如果有并发任务修改了数据的话,一个方法中的多个查询sql可能就会查出不同的结果,多个事务使用隔离级别就无法解决。

开启只读之后,就可以保证多个查询事务的查询结果是一样的
在这里插入图片描述如果只有一个查询sql就没必要添加了,如果有多个查询sql,可以视情况判断是否要添加

【6】超时时间

设置一个超时时间,如果在这个时间内事务还没有执行完,就会自动回滚这个事务,避免出现大事务

在这里插入图片描述

【7】事务失效的场景和原因

(1)事务注解只有加在public方法上才会有效

如果加在private方法,会直接爆红线;如果加在protected方法,虽然不会爆红,但是事务不会生效
在这里插入图片描述

(2)自调用会造成事务失效

没有事务的m1方法内部调用了有事务的transfer方法,但是其他方法调用m1方法的时候,transfer方法的事务会失效
在这里插入图片描述
原因就是事务注解的原理为AOP代理,代理模式只会拦截通过代理传入的方法

注解写到方法的实现类上,不要写到接口上去

(3)

(三)分布式事务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/104892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《classnames源码》阅读笔记

源码目录总览 参考官方文档中的内容&#xff0c;我们可以知道classnames 有一个主要版本&#xff08;index&#xff09;和两个替代版本 &#xff08;分别是dedupe 和 bind&#xff09;。在看目录的时候也可以发现 classnames 具有多个对外暴露的入口。 index.js是classnames的主…

Spring MVC【参数的获取与数据返回】

Spring MVC【参数的获取与上传】&#x1f34e;一. 获取参数&#x1f352;1.1 获取单个参数&#x1f352;1.2 获取多个参数&#x1f352;1.3 获取多个参数&#x1f352;1.4 获取URL中参数 (PathVariable)&#x1f34e;二. 上传文件 (RequestPart)&#x1f352;2.1 postman模拟上…

目标检测论文解读复现【NO.23】FS-YOLOv5:轻量化红外目标检测方法

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0…

33个CadQuery程序化建模实例

本文介绍的33个建模示例可以帮助你了解如何使用 CadQuery 构建3D对象。示例是从简单到复杂组织起来的&#xff0c;因此按顺序学习它们是吸收它们的最佳方式。 1、简易矩形板 最简单的例子&#xff0c;一个矩形盒子&#xff1a; result cadquery.Workplane("front&qu…

食品加工企业自营商城小程序开发,帮助企业增加销售渠道,提高销量

随着生活水平的不断提高&#xff0c;人们对于食品质量提出了更高的要求。传统人们购买食品时只能到超市或者市场进行食品采购&#xff0c;需要花费一定的时间和精力&#xff0c;而且经过多层中间商赚取差价的原因性价比也并不高。在移动电商的时代发展下&#xff0c;很多企业商…

『 canvas 动画』为了让老婆彻底理解正弦和余弦,我连夜制作了这个效果

前言 最近在做 canvas 相关的效果时&#xff0c;经常用到三角函数以及正/余弦相关的数字知识&#xff0c;这些知识点都是我们在初中的时候就学过的&#xff0c;但是这么多年基本已经忘的差不多了&#xff0c;刚好最近又学到了一个用 canvas 来实现的正/余弦动画效果&#xff0…

成功转行Python工程师,年薪30W+,经验总结都在这

这是给转行做Python的小白的参考&#xff0c;无论是从零开始&#xff0c;或者是转行的朋友来说&#xff0c;这都是值得一看的&#xff0c;也是可以作为一种借鉴吧。 而且我决定转行IT&#xff08;互联网&#xff09;行业&#xff0c;其实理由也很简单&#xff0c;不用动体力&a…

循环冗余编码(CRC编码)与海明码(考研前突击一下QAQ)

循环冗余编码&#xff08;CRC编码&#xff09;与海明码 一.环冗余编码 1.循环冗余编码的形成 生成多项式&#xff1a;G1011 表示成生成多项式为G(x)X3X1X^3X1X3X1 示例&#xff1a; 假设信息字节为&#xff1a;F1001010 选取生成多项式&#xff08;默认&#xff09;G1011 将…

2022年下半年部分团队的总结

这是 2021 年年底的汇报。 这是 2022 年上半年的汇报。 踏石留印 抓铁有痕 CSDN 是中国 IT 人士学习&#xff0c;成长&#xff0c;成功的平台。除了一些创新的探索之外&#xff0c; 20 多年来&#xff0c;CSDN 团队为这个平台开发和维护着各种基本功能和服务&#xff0c;还进…

自动化测试技术笔记(一):前期调研怎么做

昨天下午在家整理书架&#xff0c;把很多看完的书清理打包好&#xff0c;预约了公益捐赠机构上门回收。 整理的过程中无意翻出了几年前的工作记事本&#xff0c;里面记录了很多我刚开始做自动化和性能测试时的笔记。虽然站在现在的角度来看&#xff0c;那个时候无论是技术细节…

“ 这片绿茵从不缺乏天才,努力才是最终的入场券——梅西 ”

前言 想了又想还是忍不住想发布一篇文章来纪念一下2022年的卡塔尔世界杯&#xff0c;这伟大的诸神黄昏之战。4年一届的世界杯像是一把衡量时间的坐标&#xff0c;正所谓青春不过几届世界杯&#xff01;2014巴西世界杯在上初一&#xff0c;2018俄罗斯世界杯在上高二&#xff0c;…

如何成为一名合格的互联网大厂Python工程师?

Python开发工程师&#xff0c;是一个在IT行业圈子里一直都很热门的话题&#xff0c;无论是像腾讯、百度这样的大型公司&#xff0c;还是刚刚起步的初创公司&#xff0c;都会招python开发工程师。 python已成为越来越多开发者的开发语言选择&#xff0c; 而python开发工程师工资…

[附源码]计算机毕业设计Python架构的博客平台设计(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

【Python计算几何】德劳内三角剖分算法 | scatter 绘制散点图 | Dealunay 函数

猛戳&#xff01;跟哥们一起玩蛇啊 &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a; 本章我们将介绍的是计算机和领域的 Delaunay 三角剖分算法&#xff08;即德劳内三角剖分&#xff09;&#xff0c;它是一种用于将点集划分成三角形网格的算法。…

如何同时启动Android平台GB28181设备接入模块和轻量级RTSP服务模块?

技术背景 在介绍GB28181设备接入模块和轻量级RTSP服务之前&#xff0c;我们需要先搞清楚&#xff0c;二者的使用场景和技术设计的差别&#xff1a; 首先是GB28181设备接入模块&#xff1a; 为什么要设计GB28181设备接入模块&#xff1f;GB28181接入SDK&#xff0c;实现不具备…

软件:分享六款实用的软件,每一款值得收藏

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…

[XCTF]funny_video(难度2)

目录 一、题目重述 二、解题思路 1.分解音视频 2.处理音频 总结 前言 视频夹杂着一段音频&#xff0c;怎么提取&#xff1f;遇到一款新的工具&#xff01;MKVToolNix 特此记录&#xff01; 一、题目重述 一段视频&#xff0c;观看之后发现有一段还夹杂着音频。 XCTF-fu…

避坑指南!Python里面的这九个坑,坑的就是你

Python里面有一些坑&#xff0c;让你防不胜防&#xff0c;菜鸟经常会弄晕&#xff0c;而学习多年的Python老鸟也会时不时中招。小编整理了9个坑&#xff0c;都是会经常碰到的坑&#xff0c;让你大呼我曾经也碰到过! 虽然是小的问题&#xff0c;但是在实际的项目中&#xff0c;哪…

测出让人血压升高的页面崩溃,我是如何排查的

前情回顾 前几天在一次web应用测试过程中&#xff0c;前端发起了向后端接口的查询请求&#xff0c;由于后端响应较慢&#xff0c;前端一直处于等待响应返回状态。在几分钟后&#xff0c;突然页面出现让人惊悚的“噢噢&#xff0c;页面崩溃了”几个大字。 看到这几个字的一瞬间…

用于销售、报告等的 LearnDash Group Management LMS分组管理插件

目录 获取强大、直观的LearnDash LMS组管理和报告 使用 LearnDash Groups LMS分组管理插件进行 B2B 销售 节省设置分组的时间或让客户自己构建和购买&#xff01; 获取强大、直观的LearnDash LMS组管理和报告 LearnDash分组是将学生组织成逻辑单元以进行报告和课程访问的绝…