当前位置: 首页 > news >正文

【JavaEE进阶】Spring 事务和事务传播机制

目录

1.事务回顾

1.1 什么是事务

1.2 为什么需要事务

1.3 事务的操作

2. Spring 中事务的实现

2.1 Spring 编程式事务(了解)

2.2 Spring声明式事务 @Transactional

对比事务提交和回滚的日志

3. @Transactional详解

3.1 rollbackFor

3.2 @Transactional 注解什么时候会失效

3.3 事务的隔离级别

3.3.1 MySQL 事务隔离级别

3.3.2 Spring 事务隔离级别

3.4 Spring 事务传播机制

3.4.1 什么是事务传播机制

3.4.2 事务的传播机制有哪些


1.事务回顾

1.1 什么是事务

事务是一组操作的集合, 是一个不可分割的操作:
事务会把所有的操作作为一个整体, 一起向数据库提交或者是撤销操作请求, 所以这组操作要么同时成功, 要么同时失败.

1.2 为什么需要事务

我们在进行程序开发时,也会有事务的需求
比如转账操作:
第一步: A账户 -100 元.
第二步: B 账户 +100 元
如果没有事务,第一步执行成功了, 第二步执行失败了, 那么A 账户的100 元就平白无故消失了.    如果使用事务就可以解决这个问题, 让这一组操作要么一起成功, 要么一起失败.

比如秒杀系统,
第一步: 下单成功
第二步:  扣减库存
下单成功后, 库存也需要同步减少, 如果下单成功, 库存扣减失败, 那么就会造成下单超出的情况.  所以就需要把这两步操作放在同一个事务中. 要么一起成功, 要么一起失败.

理解事务概念为主, 实际企业开发时, 并不是简单的通过事务来处理。

1.3 事务的操作

事务的操作主要有三步: 

-- 开启事务 
start transaction;-- 提交事务 
commit;-- 回滚事务 
rollback;

2. Spring 中事务的实现

Spring 中的事务操作分为两类:
1.编程式事务 (手动写代码操作事务)
2.声明式事务 (利用注解自动开启和提交事务)

在学习事务之前, 我们先准备数据和数据的访问代码
需求: 用户注册, 注册时在日志表中插入一条操作记录.

数据准备:

-- 创建数据库 
DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;use trans_test;
-- ⽤⼾表 
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR (128) NOT NULL,`password` VARCHAR (128) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '⽤⼾表';-- 操作⽇志表 
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (`id` INT PRIMARY KEY auto_increment,`user_name` VARCHAR ( 128 ) NOT NULL,`op` VARCHAR ( 256 ) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now() 
) DEFAULT charset 'utf8mb4';

代码准备:

model层:

mapper层: 

server层: 

2.1 Spring 编程式事务(了解)

Spring 手动操作事务和上面 MySOL操作事务类似,有3个重要操作步骤:

SpringBoot 内置了两个对象:


我们还是根据代码的实现来学习:

package com.example.trans.controller;import com.example.trans.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@Autowiredprivate UserService userService;@RequestMapping("register")public Boolean register(String username, String password) {//开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);Integer result = userService.insert(username, password);System.out.println("插入用户表, result: " + result);//回滚事务
//        dataSourceTransactionManager.rollback(transaction);//提交事务dataSourceTransactionManager.commit(transaction);return true;}
}

 这部分代码了解即可:

以上代码虽然可以实现事务,但操作也很繁琐,有没有更简单的实现方法呢?
接下来我们学习声明式事务

2.2 Spring声明式事务 @Transactional

声明式事务的实现很简单

在需要事务的方法上添加 @Transactional

注解就可以实现了.无需手动开启事务和提交事务, 进入方法时自动开启事务, 方法执行完会自动提交事务, 如果中途发生了没有处理的异常会自动回滚事务.

我们来看代码实现:

@RequestMapping("/trans")
@RestController
public class TransController {@AutowiredUserService userService;@AutowiredLogService logService;@Transactional@RequestMapping("/register")public Boolean register(String userName, String password) {Integer result = userService.insert(userName, password);System.out.println("插入用户表, result: " + result);return true;}
}

运行程序, 发现数据插入成功

修改程序,使之出现异常

运行程序:


发现虽然日志显示数据插入成功, 但数据库却没有新增数据, 事务进行了回滚

我们一般会在业务逻辑层当中来控制事务, 因为在业务逻辑层当中, 一个业务功能可能会包含多个数据访问的操作, 在业务逻辑层来控制事务, 我们就可以将多个数据访问操作控制在一个事务范围内上述代码在Controller中书写,  只是为了方便学习.

@Transactional作用

@Transactional 可以用来修饰方法或类:

方法/类 被 @Transactional 注解修饰时, 在目标方法执行开始之前, 会自动开启事务, 方法执行结束
之后,自动提交事务.

如果在方法执行过程中, 出现异常, 且异常未被捕获, 就进行事务回滚操作

如果异常被程序捕获, 方法就被认为是成功执行, 依然会提交事务,

运行程序, 事务成功提交,: 

在上述程序中, 发现虽然程序出错了, 但是由于异常被捕获了, 所以事务依然得到了提交

如果需要事务进行回滚, 有以下两种方式:

1.重新抛出异常

2.手动回滚事务

对比事务提交和回滚的日志

事务提交时:

事务回滚时:

当事务提交时, 日志会含有: Transaction synchronization committing SqlSession

3. @Transactional详解

通过上面的代码, 我们学习了 @Transactional 的基本使用. 接下来我们学习 @Transactional
注解的使用细节.

我们主要学习 @Transactional 注解当中的三个常见属性:
1. rollbackFor: 异常回滚属性, 指定能够触发事务回滚的异常类型, 可以指定多个异常类型
2.lsolation: 事务的隔离级别. 默认值为 Isolation.DEFAULT
3. propagation: 事务的传播机制. 默认值为 Propagation.REQUIRED


3.1 rollbackFor

  • 默认情况下,Spring 的事务管理器只会在抛出运行时异常(RuntimeException及其子类)和错误(Error)时才会回滚事务。这是因为在 Java 的异常体系中,非运行时异常(例如IOExceptionSQLException等检查异常)通常被认为是可以预期和合理处理的情况。
  • 例如,如果你有一个方法是从文件中读取数据,可能会抛出IOException。在这种情况下,开发人员可能希望在捕获这个异常后进行一些特定的处理,比如记录日志、提示用户重新输入等操作,而不是直接回滚事务。

验证抛出IOException异常, 事务提交:

 运行程序, 事务成功提交:

如果我们需要所有异常都回滚, 需要来配置 @Transactional 注解当中的 rollbackFor 属性, 通
过 rollbackFor 这个属性指定出现何种异常类型时事务进行回滚.

结论:

1.在Spring的事务管理中,默认只在遇到运行时异常 RuntimeException 和 Error 时才会回滚

2.如果需要回滚指定类型的异常, 可以通过 rollbackFor 属性来指定 

3.2 @Transactional 注解什么时候会失效

1. 方法的访问权限问题

情况说明:如果@Transactional注解标记的方法是private的,那么这个注解将会失效。这是因为 Spring 事务管理是基于代理的机制来实现的,代理对象无法访问目标对象的private方法。

示例代码

import org.springframework.transaction.annotation.Transactional;
public class TransactionalService {@Transactionalprivate void privateTransactionalMethod() {// 业务逻辑}
}

解释:在这个示例中,privateTransactionalMethod方法虽然被标注了@Transactional,但是由于它是private方法,Spring 无法为其创建有效的代理来管理事务,所以该注解实际上不会起作用。

2. 方法内部调用自身方法的情况

情况说明:当一个类中的方法 A 调用了同一个类中的另一个被@Transactional注解标记的方法 B,并且这个调用是在方法 A 内部直接调用(而不是通过代理对象调用)时,方法 B 上的@Transactional注解会失效。这是因为在这种情况下,没有经过 Spring 的代理拦截,也就无法开启事务管理。

示例代码

import org.springframework.transaction.annotation.Transactional;
public class TransactionalService {public void outerMethod() {innerTransactionalMethod();}@Transactionalpublic void innerTransactionalMethod() {// 业务逻辑}
}

解释:在这个例子中,outerMethod直接调用innerTransactionalMethod,这种内部调用不会触发 Spring 的事务代理,所以innerTransactionalMethod上的@Transactional注解在这里不会产生事务管理的效果。

3. 异常被捕获但没有重新抛出的情况

情况说明@Transactional注解默认是在运行时异常(RuntimeException)和错误(Error)抛出时才会回滚事务。如果在被@Transactional注解标记的方法中捕获了异常,并且没有重新抛出(对于需要回滚事务的异常类型),那么事务将不会回滚。

示例代码

import org.springframework.transaction.annotation.Transactional;
public class TransactionalService {@Transactionalpublic void methodWithTransaction() {try {// 业务逻辑,可能会抛出RuntimeExceptionthrow new RuntimeException("模拟异常");} catch (RuntimeException e) {// 捕获异常但没有重新抛出}}
}

解释:在这个示例中,methodWithTransaction方法中虽然抛出了RuntimeException,但是在捕获这个异常后没有重新抛出,所以事务不会回滚。

4.数据库不支持事务或者事务配置错误的情况

情况说明:如果使用的数据库本身不支持事务(虽然这种情况比较少见,大多数主流数据库都支持事务),或者在 Spring 配置中事务相关的配置(如数据源、事务管理器等)出现错误,那么@Transactional注解也会失效。

5. 使用了不兼容的事务传播行为组合

情况说明:在多个方法嵌套调用并且每个方法都有@Transactional注解的情况下,如果事务传播行为组合不兼容,可能会导致事务失效或者不符合预期。例如,在一个方法中使用REQUIRES_NEW传播行为,而在嵌套调用的方法中使用NEVER传播行为,这可能会导致事务无法正常开启或者出现冲突。

示例代码

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class TransactionalService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void outerMethod() {innerMethod();}@Transactional(propagation = Propagation.NEVER)public void innerMethod() {// 业务逻辑}
}

解释:在这个例子中,outerMethod要求开启一个新事务(REQUIRES_NEW),而innerMethod却声明不允许在事务中执行(NEVER),这种不兼容的传播行为组合可能会导致事务管理出现问题,使得@Transactional注解无法按照预期工作。

3.3 事务的隔离级别

3.3.1 MySQL 事务隔离级别

SQL标准定义了四种隔离级别, MySQL全都支持, 这四种隔离级别分别是:

1.读未提交(READ UNCOMMITTED): 读未提交, 也叫未提交读, 该隔离级别的事务可以看到其他事务中未提交的数据.

因为其他事务未提交的数据可能会发生回滚,但是该隔离级别却可以读到,我们把该级别读到的数据称之为脏数据,这个问题称之为脏读。

2.读提交(READ COMMITTED): 读已提交, 也叫提交读, 该隔离级别的事务能读取到已经提交事务的数据.

该隔离级别不会有脏读的问题, 但由于在事务的执行中可以读取到其他事务提交的结果, 所以在不同时间的相同 SOL 查询可能会得到不同的结果, 这种现象叫做不可重复读

3. 可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也就可以确保同一事务多次查询的结果一致, 但是其他事务新插入的数据, 是可以感知到的. 这也就引发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.

比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因).明明在事务中查询不到这条信息,但自己就是插入不进去,这个现象叫幻读.

4.串行化(SERIALIZABLE): 序列化, 事务最高隔离级别, 它会强制事务排序, 使之不会发生冲突, 从而解决了脏读, 不可重复读和幻读问题, 但因为执行效率低,所以真正使用的场景并不多,

  1. 读未提交(Read Uncommitted)

    • 定义:这是最低的隔离级别。在这个级别下,一个事务可以读取到另一个事务未提交的数据。这就可能导致脏读(Dirty Read)的问题。
    • 脏读示例:假设有两个事务,事务 A 和事务 B。事务 A 修改了一条记录但尚未提交,事务 B 此时读取了这条被修改的记录。如果事务 A 后来回滚了修改,那么事务 B 读取到的数据就是 “脏” 数据,这种情况就是脏读。例如,事务 A 将账户余额从 100 元修改为 200 元,但还没提交,事务 B 读取账户余额为 200 元,然后事务 A 回滚,实际余额还是 100 元,事务 B 读取的数据就不准确了。
    • 应用场景:这种隔离级别一般很少在实际生产环境中使用,因为脏读问题可能会导致数据的不一致性。不过在一些对数据准确性要求不高,并且需要最大程度提高性能和并发度的场景下,可能会考虑使用,比如某些数据分析系统,对数据的实时性要求高于准确性。
  2. 读已提交(Read Committed)

    • 定义:在这个隔离级别下,一个事务只能读取另一个事务已经提交的数据,避免了脏读的问题。但是可能会出现不可重复读(Non - Repeatable Read)的情况。
    • 不可重复读示例:事务 A 在执行过程中,两次读取同一条记录,在两次读取之间,事务 B 修改并提交了这条记录。这样事务 A 两次读取的结果就不一样了。例如,事务 A 先读取账户余额为 100 元,然后事务 B 将余额修改为 200 元并提交,事务 A 再次读取余额就变成了 200 元,这就是不可重复读。
    • 应用场景:在很多对数据准确性有一定要求的业务场景中比较常用,比如一般的 Web 应用程序中的查询操作,大多数情况下可以接受不可重复读的情况,因为这些查询通常是获取最新的数据状态。
  3. 可重复读(Repeatable Read)

    • 定义:在这个隔离级别下,一个事务在执行过程中多次读取同一数据会得到相同的结果,不会出现不可重复读的情况。不过,在这个级别下可能会出现幻读(Phantom Read)的情况。
    • 幻读示例:事务 A 在执行过程中,根据某个条件查询记录,第一次查询得到了一定数量的记录。在事务 A 还未结束时,事务 B 插入了符合事务 A 查询条件的新记录并提交。当事务 A 再次根据相同条件查询时,就会发现比第一次查询多了一些记录,就好像出现了 “幻影” 一样。例如,事务 A 查询年龄大于 30 岁的员工名单,第一次查询有 5 个人,然后事务 B 插入了一个年龄大于 30 岁的新员工记录并提交,事务 A 再次查询就有 6 个人了。
    • 应用场景:对于一些对数据一致性要求较高的业务场景,如金融系统中的账户交易记录查询等,可重复读是比较合适的隔离级别。它可以保证在一个事务内部,对同一数据的读取是稳定的。
  4. 串行化(Serializable)

    • 定义:这是最高的隔离级别。在这个级别下,事务是串行执行的,一个事务必须等待前一个事务完成后才能开始,就像把多个事务的执行顺序排好队一样。这样可以避免脏读、不可重复读和幻读的问题。
    • 应用场景:在对数据准确性和一致性要求极高的场景下使用,如一些涉及到高价值交易或者重要数据修改的系统,像银行的核心账务系统等。不过,这种隔离级别会严重影响系统的并发性能,因为事务是串行执行的,所以在使用时需要权衡性能和数据一致性的需求。

3.3.2 Spring 事务隔离级别

Spring 中事务隔离级别有5 种:

package org.springframework.transaction.annotation;public enum Isolation {DEFAULT(-1),READ_UNCOMMITTED(1),READ_COMMITTED(2),REPEATABLE_READ(4),SERIALIZABLE(8);private final int value;private Isolation(int value) {this.value = value;}public int value() {return this.value;}
}

Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置

@Transactional(isolation = Isolation.READ_COMMITTED)

3.4 Spring 事务传播机制

3.4.1 什么是事务传播机制

事务传播机制就是: 多个事务方法存在调用关系时, 事务是如何在这些方法间进行传播的。

比如有两个方法 A, B 都被 @Transactional 修饰,A方法调用B方法

A方法运行时, 会开启一个事务. 当A调用B时, B方法本身也有事务, 此时B方法运行时, 是加入A的事务, 还是创建一个新的事务呢?

这个就涉及到了事务的传播机制.

比如公司流程管理

执行任务之前,需要先写执行文档,任务执行结束,再写总结汇报

此时A部门有一项工作, 需要B部门的支援, 此时B部门是直接使用A部门的文档, 还是新建一个文档呢?

事务隔离级别解决的是多个事务同时调用一个数据库的问题

而事务传播机制解决的是一个事务在多个节点(方法)中传递的问题

3.4.2 事务的传播机制有哪些

@Transactional 注解支持事务传播机制的设置, 通过 propagation 属性来指定传播行为

Spring 事务传播机制有以下7种:

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;}
}

比如一对新人要结婚了, 关于是否需要房子

1.REQUIRED(默认)

  • 定义:如果当前没有事务,就创建一个新事务;如果当前已经存在一个事务,就加入这个事务。这是最常用的传播机制。
  • 示例场景
    • 假设我们有一个业务方法 A 调用另一个业务方法 B,方法 A 已经开启了一个事务。当方法 B 使用REQUIRED传播机制时,它会直接加入到方法 A 的事务中。例如,在一个电商系统中,下单操作(方法 A)开启了一个事务,在下单过程中需要更新库存(方法 B),方法 B 就可以使用REQUIRED传播机制加入到下单事务中,保证下单和库存更新要么都成功,要么都失败。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {// 加入methodA的事务中
}
 

2.SUPPORTS

  • 定义:如果当前存在事务,就加入当前事务;如果当前没有事务,就以非事务方式执行。
  • 示例场景
    • 考虑一个日志记录方法。如果在一个事务性的业务操作过程中调用它,它可以加入事务,保证日志记录和业务操作一起成功或失败;但如果是在非事务环境下调用,它也能正常工作,只是不会有事务管理。例如,在一个用户注册系统中,注册方法(有事务)可能会调用记录注册日志的方法,日志方法使用SUPPORTS传播机制,就可以在注册事务中记录日志;而单独测试日志方法时,它也能正常记录日志而不需要事务。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {// 如果methodA有事务就加入,没有就非事务执行
}
 

3.MANDATORY

  • 定义:如果当前存在事务,就加入当前事务;如果当前没有事务,就抛出异常。
  • 示例场景
    • 想象一个必须在事务环境下执行的关键业务操作,比如在一个资金转账系统中,有一个计算转账手续费的方法,这个方法必须在转账事务中执行,因为手续费的计算和转账操作紧密相关。如果调用这个方法时没有事务,就应该抛出异常,提醒开发人员必须在事务环境下调用。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {// 如果没有事务就抛出异常,有事务就加入
}
 

4.REQUIRES_NEW

  • 定义:不管当前是否存在事务,都创建一个新事务。如果当前已经存在一个事务,就先暂停当前事务,等新事务执行完毕后,再恢复原来的事务。
  • 示例场景
    • 在一个电商系统中,下单操作(有事务)可能需要调用一个发送通知的方法。发送通知的操作应该独立于下单事务,即使下单事务回滚,通知也已经发送出去了。所以发送通知的方法可以使用REQUIRES_NEW传播机制,开启一个新事务来发送通知。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {// 开启新事务,与methodA的事务独立
}
 

5.NOT_SUPPORTED

  • 定义:以非事务方式执行操作,并且如果当前存在事务,就先暂停当前事务,等操作执行完毕后,再恢复原来的事务。
  • 示例场景
    • 假设在一个事务性的业务流程中,需要调用一个外部的统计服务。这个统计服务本身不需要事务管理,而且为了不影响原来事务的性能,最好以非事务方式执行。例如,在一个订单处理系统中,有一个事务性的订单审核方法,在审核过程中需要调用一个外部的订单统计服务,这个统计服务就可以使用NOT_SUPPORTED传播机制,暂停审核事务,执行完统计后再恢复审核事务。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() {// 暂停methodA的事务,非事务执行,然后恢复methodA的事务
}
 

6.NEVER

  • 定义:以非事务方式执行操作,如果当前存在事务,就抛出异常。
  • 示例场景
    • 考虑一个简单的查询方法,它只是用于快速获取数据,不应该在事务环境下执行。如果在一个有事务的上下文中调用这个查询方法,就应该抛出异常,因为它可能会影响查询性能或者不符合设计意图。例如,在一个数据查询接口中,有一个简单的获取用户基本信息的方法,这个方法可以使用NEVER传播机制,确保它不会在事务环境下执行。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.NEVER)
public void methodB() {// 如果有事务就抛出异常,以非事务执行
}
 

7.NESTED

  • 定义:如果当前存在事务,就在当前事务中嵌套一个子事务。子事务可以独立于父事务提交或回滚,但是如果父事务回滚,子事务也会回滚。
  • 示例场景
    • 在一个复杂的业务流程中,可能有一个主业务操作和一些附属的子业务操作。例如,在一个订单处理系统中,主订单处理事务(父事务)可能包含一个子事务,如更新相关的推荐商品信息。如果推荐商品信息更新成功(子事务成功),但主订单处理失败(父事务失败),那么子事务也会回滚;而如果子事务失败,父事务可以根据具体情况决定是否继续执行或者也回滚。
  • 代码示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {// 事务开始methodB();// 事务提交或回滚
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {// 在methodA的事务中创建嵌套子事务
}

总结

 

相关文章:

【JavaEE进阶】Spring 事务和事务传播机制

目录 1.事务回顾 1.1 什么是事务 1.2 为什么需要事务 1.3 事务的操作 2. Spring 中事务的实现 2.1 Spring 编程式事务(了解) 2.2 Spring声明式事务 Transactional 对比事务提交和回滚的日志 3. Transactional详解 3.1 rollbackFor 3.2 Transactional 注解什么时候会…...

Flink1.19编译并Standalone模式本地运行

1.首先下载源码 2.本地运行 新建local_conf和local_lib文件夹,并且将编译后的文件放入对应的目录 2.1 启动前参数配置 2.1.2 StandaloneSessionClusterEntrypoint启动参数修改 2.1.3 TaskManagerRunner启动参数修改 和StandaloneSessionClusterEntrypoint一样修改…...

gitlab-development-kit部署gitlab《二》

gitlab-development-kit部署gitlab《一》 环境 mac 12.7.4 xcode 14.2 gdk 0.2.16 gitlab-foss 13.7 QA xcode源码安装 # https://crifan.github.io/xcode_dev_summary/website/xcode_dev/install_xcode/ # https://xcodereleases.comopenssl1.1 源码安装 # https://open…...

Java面试之多线程并发篇(3)

前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!SynchronizedMap和ConcurrentHashMap有什么区别?什么是线程安全?Thread类中的yield方法有什么作用?Java线程池中submit() 和 execute()方法有…...

任何使用 Keras 进行迁移学习

在前面的文章中,我们介绍了如何使用 Keras 构建和训练全连接神经网络(MLP)、卷积神经网络(CNN)和循环神经网络(RNN)。本文将带你深入学习如何使用 迁移学习(Transfer Learning&#…...

Mac 使用mac 原生工具将mp4视频文件提取其中的 mp3 音频文件

简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖…已保研 学习经验:扎实基础 + 多做笔…...

【SQL】一文速通SQL

SQL知识概念介绍 1. Relation Schema vs Relation Instance 简单而言,Relation Schema 是一个表,有变量还有数据类型 R (A1, A2, … , An) e.g. Student (sid: integer, name: string, login: string, addr: string, gender: char) Relation insta…...

【学习】【HTML】块级元素,行内元素,行内块级元素

块级元素 块级元素是 HTML 中一类重要的元素&#xff0c;它们在页面布局中占据整行空间&#xff0c;通常用于创建页面的主要结构组件。 常见的块级元素有哪些&#xff1f; <div>: 通用的容器元素&#xff0c;常用于创建布局块。<p>&#xff1a;段落元素&#xf…...

握手协议是如何在SSL VPN中发挥作用的?

SSL握手协议&#xff1a;客户端和服务器通过握手协议建立一个会话。会话包含一组参数&#xff0c;主要有会话ID、对方的证书、加密算法列表&#xff08;包括密钥交换算法、数据加密算法和MAC算法&#xff09;、压缩算法以及主密钥。SSL会话可以被多个连接共享&#xff0c;以减少…...

机器学习 - 为 Jupyter Notebook 安装新的 Kernel

https://ipython.readthedocs.io/en/latest/install/kernel_install.html 当使用jupyter-notebook --no-browser 启动一个 notebook 时&#xff0c;默认使用了该 jupyter module 所在的 Python 环境作为 kernel&#xff0c;比如 C:\devel\Python\Python311。 如果&#xff0c…...

CTF攻防世界小白刷题自学笔记13

1.fileinclude,难度&#xff1a;1,方向&#xff1a;Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接&#xff1a;攻防世界Web方向新手模式第16题。 打开一看给了很多提示&#xff0c;什么language在index.php的第九行&#xff0c;flag在flag.php中&#xff0c;但事情显…...

Rust 模板匹配——根据指定图片查找处于大图中的位置(支持GPU加速)

Rust 模板匹配——根据指定图片查找处于大图中的位置(支持GPU加速) 01 前言 在手搓RPA工具的时候,总会碰到不好定位的情况,那么,就需要根据小图来找到对应屏幕上的位置(以图识图),这个需求也比较简单。想到市面上也有不少RPA工具都有这个功能,那么人家有的,俺也可以…...

JVM详解:类的加载过程

JVM中类的加载主要分为三个部分&#xff0c;分别为加载&#xff08;loading&#xff09;&#xff0c;链接&#xff08;linking&#xff09;&#xff0c;初始化&#xff08;initing&#xff09;。其中加载负责的主要是讲类文件加载到内存中变为类对象&#xff0c;不过此时只有基…...

Python →爬虫实践

爬取研究中心的书目 现在&#xff0c;想要把如下网站中的书目信息爬取出来。 案例一 耶鲁 Publications | Yale Law School 分析网页&#xff0c;如下图所示&#xff0c;需要爬取的页面&#xff0c;标签信息是“<p>”&#xff0c;所以用 itemssoup.find_all("p&…...

Visitor 访问者模式

1)意图 表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义用于这些元素的新操作。 2)结构 访问者模式的结构图如图 7-48 所示。 其中: Visitor(访问者) 为该对象结构中ConcreteElement 的每一个类声明一个 Vsit 操作。该操作的名字和特征标识…...

Mac解压包安装MongoDB8并设置launchd自启动

记录一下在mac上安装mongodb8过程&#xff0c;本机是M3芯片所以下载m芯片的安装包&#xff0c;intel芯片的类似操作。 首先下载安装程序包。 # M芯片下载地址 https://fastdl.mongodb.org/osx/mongodb-macos-arm64-8.0.3.tgz # intel芯片下载地址 https://fastdl.mongodb.org…...

Springboot采用jasypt加密配置

目录 前言 一、Jasypt简介 二、运用场景 三、整合Jasypt 2.1.环境配置 2.2.添加依赖 2.3.添加Jasypt配置 2.4.编写加/解密工具类 2.5.自定义加密属性前缀和后缀 2.6.防止密码泄露措施 2.61.自定义加密器 2.6.2通过环境变量指定加密盐值 总结 前言 在以往的多数项目中&#xff0…...

加载shellcode

​​​​​​ #include <stdio.h>#include <windows.h>DWORD GetHash(const char* fun_name){ DWORD digest 0; while (*fun_name) { digest ((digest << 25) | (digest >> 7)); //循环右移 7 位 digest *fun_name; //累加…...

K8S如何基于Istio实现全链路HTTPS

K8S如何基于Istio实现全链路HTTPS Istio 简介Istio 是什么?为什么选择 Istio?Istio 的核心概念Service Mesh(服务网格)Data Plane(数据平面)Sidecar Mode(边车模式)Ambient Mode(环境模式)Control Plane(控制平面)Istio 的架构与组件Envoy ProxyIstiod其他组件Istio 的流量管…...

React Query在现代前端开发中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 引言 React Query …...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...