【Spring】Spring事务和事务传播机制

news2024/11/16 7:42:08

在这里插入图片描述

文章目录

  • 什么是事务
  • 事务的操作
  • Spring 中事务的实现
    • Spring编程式事务
    • Spring 声明式事务 @Transactional
      • @Transactional作用
      • @Transactional 详解
        • rollbackFor
        • 事务隔离级别
        • Spring 事务隔离级别
        • Spring 事务传播机制

什么是事务

事务(Transaction)是一个程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败)。在计算机术语中,事务通常是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL、C++、Java)书写的用户程序的执行所引起,并用形如BeginTransaction和EndTransaction语句(或函数调用)来界定。

前面我们学习 MySQL 的时候,也为大家介绍了关于事务方面的知识,事务具有以下特性:

  1. 原子性(Atomicity):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。原子性可以消除系统处理操作子集的可能性。
  2. 一致性(Consistency):事务在完成时,必须使所有的数据都保持一致状态。事务可以保证数据库的完整性,避免因各种原因而导致数据库的内容不一致,产生错误的数据。
  3. 隔离性(Isolation):事务处理过程中的中间状态对其他事务是透明的。事务隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  4. 持续性(Durability):持续性是指事务一旦提交,它对数据库中数据的改变是永久性的。接下来的操作或故障不应对其有任何影响。

当我们在进行转账或者购物的时候,往往需要用到事务操作,为什么呢?假设我向别人转账 100 元,我钱已经转过去了,但是在对方接收的时候出现了问题,那么我自己账户上的余额少了 100,但是对方的账户上却没有收到我的 100,这种现象是绝对不可以出现的。有了事务的插足,如果在我们钱已经转出去了情况,但是在对方收的过程中发生问题的话,事务就会进行回滚,发出方的 100 元就不会扣掉。

事务的操作

事务的操作主要为下面三个部分:

  1. 开启事务:start transaction/begin(一组操作前开启事务)
  2. 提交事务:commit(这组操作全部成功,提交事务)
  3. 回滚事务:rollback(这组操作中间任何一个操作出现异常,并且这个异常没有被处理,就是回滚事务)

Spring 中事务的实现

在 Spring 中实现事务的方式有两种:

  1. 编程式事务(手动写代码操作事务)
  2. 声明式事务(利用注解自动开启事务和提交事务)

这篇文章为大家介绍事务,主要通过操作数据库的操作来体现,所以我们先准备两个表:

-- 创建数据库
DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;
-- 用户表
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';

配置 MyBatis:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/trans_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**Mapper.xml

为对应的表创建 model:

import lombok.Data;

import java.util.Date;

@Data
public class UserInfo {
    private int id;
    private String userName;
    private String password;
    private Date createTime;
    private Date updateTime;
}
import lombok.Data;

import java.util.Date;

@Data
public class LogInfo {
    private int id;
    private String userName;
    private String op;
    private Date createTime;
    private Date updateTime;
}

MyBatis 操作数据库:

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserInfoMapper {
    @Insert("insert into user_info (·user_name·,`password`) values (#{userName},#{password})")
    Integer insert(String userName, String password);
}
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface LogInfoMapper {
    @Insert("insert into log_info (`name`, `op`) values (#{name},#{op})")
    Integer insertLog(String name,String op);
}

Service 层:

import com.example.springtransaction.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    public void registryUser(String name, String password) {
        userInfoMapper.insert(name, password);
    }
}
import com.example.springtransaction.mapper.LogInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LogInfoService {
    @Autowired
    private LogInfoMapper logInfoMapper;

    public void insertLog(String name, String op) {
        logInfoMapper.insertLog(name,op);
    }
}

Contoller 层:

import com.example.springtransaction.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserInfoController {
    @Autowired
    private UserInfoService userInfoService;

    @RequestMapping("/registry")
    public String  registry(String name, String password) {
        userInfoService.registryUser(name, password);
        return "注册成功";
    }
}
import com.example.springtransaction.service.LogInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/log")
@RestController
public class LogInfoController {
    @Autowired
    private LogInfoService logInfoService;

    @RequestMapping("/insert")
    public String insertLog(String name, String op) {
        logInfoService.insertLog(name, op);
        return "日志插入成功";
    }
}

Spring编程式事务

Spring 手动操作事务,有三个重要步骤:

  1. 开启事务(获取事务)
  2. 提交事务
  3. 回滚事务

在 Spring 中如何获取到事务呢?

要想获取到事务,我们需要借助 Spring 内置的两个对象:

  • DataSourceTransactionManager:事务管理器,用来获取事务(开启事务),提交或回滚事务
  • TransactionDefinition:事务的属性,在获取事务的时候需要将 TransactionDefinition 传递进去从而获得一个事务 TransactionStatus
import com.example.springtransaction.service.UserInfoService;
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 UserInfoController {
    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/registry")
    public String  registry(String name, String password) {
        //开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        userInfoService.registryUser(name, password);
        //提交事务
        dataSourceTransactionManager.commit(transactionStatus);
        return "注册成功";
    }
}

访问 127.0.0.1:8080/user/registry 之后,我们查看日志:

在这里插入图片描述

观察表可以发现数据插入成功:

在这里插入图片描述

这个是事务提交成功的日志,然后我们再来看看当事务回滚之后会出现什么日志:

//回滚事务
dataSourceTransactionManager.rollback(transactionStatus);

在这里插入图片描述
可以看到,当发生事务回滚的时候,就只有打开 sqlSession 和关闭 sqlSession 的操作,没有 commit 提交的操作,并且观察数据库可以发现,并没有插入数据:

在这里插入图片描述
通过编程式实现事务操作比较复杂,而使用声明式事务就简单很多。

Spring 声明式事务 @Transactional

Spring 声明式实现事务很简单,只需要加上 @Transactional 注解就可以实现了,无需手动开启和提交事务,进入方法的时候会自动开始事务,中途发生了未处理的异常就会自动回滚事务。跟前面的 AOP 统一功能处理是一样的,方法开始前干什么,结束后干什么,抛出异常后干什么。

import com.example.springtransaction.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/trans")
@RestController
public class TransactionalController {
    @Autowired
    private UserInfoService userInfoService;

    @Transactional
    @RequestMapping("/registry")
    public String registry(String name, String password) {
        userInfoService.registryUser(name,password);
        return "注册成功";
    }
}

在这里插入图片描述
在这里插入图片描述
我们在这个方法中制造出异常,看是否会发生事务的回滚:

System.out.println(10/0);

在这里插入图片描述

没有提交事务就说明发生了事务的回滚。

在这里插入图片描述

@Transactional作用

@Transactional 可以修饰方法,也可以修饰类:

  • 修饰方法时:只有修饰 public 方法的时候才会生效(修饰其他权限的方法的时候不会报错,但是也不会生效)【推荐】
  • 修饰类时:对 @Transactional 修饰的类中所有的 public 方法都生效

当类/方法被 @Transactional 修饰的时候,在目标方法执行之前,就会自动开启事务,方法执行结束之后,会自动结束事务。但是如果在方法执行的过程中出现了异常,并且异常没有被正确捕获的话,就会进行事务的回滚操作;如果这个异常被成功捕获,那么方法就会被认为是正常执行,事务就会被正常提交。

我们对上面制造的异常进行捕获:

try {
    System.out.println(10/0);
} catch (Exception e) {
    e.printStackTrace();
}

在这里插入图片描述

事务被提交,并且数据库的插入操作成功:

在这里插入图片描述

如果我们想要自己控制事务的回滚,有两种方式可以达到:

(1)重新抛出异常:

try {
    System.out.println(10/0);
} catch (Exception e) {
    throw e;
}

在这里插入图片描述
在这里插入图片描述
(2)手动回滚事务:

首先我们需要通过 TransactionAspectSupport.currentTransactionStatus()方法来获取到当前事务,然后再调用 setRollbackOnly 进行事务的回滚操作:

try {
    System.out.println(10/0);
} catch (Exception e) {
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

@Transactional 详解

上面我们了解了 @Transactional 的基本使用,那么接下来我们将详细学习一下 @Transactional 注解。

在这里插入图片描述
@Transactional 注解中的属性有很多,但是我们主要学习这三个属性:

  1. rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型,默认可以发生事务回滚的异常类型是 RuntimeException 及其子类以及 Error ,可以指定多个异常类型
  2. Isolation:事务的隔离级别。默认值为 Isolation.DEFAULT
  3. propagation:事务的传播机制。默认值为 Propagation.REQUIRED
rollbackFor

@Transactional 默认只会在发生运行时异常和 Error 的时候才会发生事务的回滚操作:

在这里插入图片描述
假设我们抛出的异常是非运行时异常:

try {
    System.out.println(10/0);
} catch (Exception e) {
    throw new IOException();
}

在这里插入图片描述
在这里插入图片描述

可以看到,当抛出的异常类型是非运行异常的时候,不会发生事务的回滚。

如果我们想指定,发生非运行异常的时候也能进行事务回滚的操作的话,我们就需要配置 @Transactional 注解中的 rollbackFor 属性:

@Transactional(rollbackFor = Exception.class)

在这里插入图片描述
抛出非运行时异常的时候,也进行了事务的回滚操作。

结论:

  • 在 Spring 的事务管理中,默认只在遇到运行时异常 RuntimeException 和 Error 的时候才会回滚
  • 如果需要回滚指定类型的异常,可以通过 rollbackFor 属性来指定
事务隔离级别

事务的隔离级别有下面几种:

  1. 未提交读(Read Uncommitted):最低的事务隔离级别,允许读取尚未提交的事务数据。这意味着可能会出现脏读、不可重复读和幻读的情况。
  • 该隔离级别可以读到其他事务未提交的数据,但是如果其他事务发生了事务回滚的话,那么我们读到的数据就是“脏数据”,这个问题被称为脏读
  1. 提交读(Read Committed):在事务执行过程中,只允许读取已经提交的数据。这样可以避免脏读问题,但仍然可能出现不可重复读和幻读。
  • 该隔离级别可以避免出现脏读的情况,但是由于该隔离级别可以读取到其他事务已提交的数据,所以在不同时间段读取到的数据可能是不同的,这种现象叫做不可重复读
  1. 可重复读(Repeatable Read):在这个级别中,事务在其生命周期内可以多次读取同一个数据,而不会看到其他事务对该数据的修改。这可以避免脏读和不可重复读问题,但仍然可能出现幻读。
  • 假设该事务级别的事务正在读取数据,并且在此期间,其他事务又插入了新的数据,因为该隔离级别下读取到的数据都是一样的,所以就无法读取到新插入的这条数据,当前事务再插入这条数据的时候,因为唯一主键的约束,就无法成功插入,,但是在当前事务中又查询不到这条数据,又插入不成功,所以就出现了幻读的情况
  1. 可串行化(Serializable):最高的事务隔离级别,通过强制事务串行执行,避免了脏读、不可重复读和幻读问题。但这种级别的性能开销较大,因为事务必须串行执行。

给大家举个例子:假设我要考试了,但是考试前两天我去老师办公室叫作业,我看见老师电脑上显示的是 2024年高数期末考试试卷草稿,所以我就将试卷给拍了下来,然后回到了寝室就只琢磨复习试卷上出现的题目就,等到考试那天我信心满满的走进考场,但是当我看到试卷的那一刻,我懵了,很多题目都不一样。这是因为我那天看到的只是草稿,在我走后老师又对其进行了修改,这就是脏读的问题。

假设我工厂生产机器,要生产两批不同的机器,A机器生产100台,B机器生产50台,先生产的是 A 机器,我按照给定的图纸来制造,当制造了 95 台 A 机器的时候,上面就将 B 机器的图纸传过来了,但是我不知道,我知道的就是按照图纸来造,这样就导致了 A 机器制造的数量不够,这就是不可重复读的问题。

假设公司让我们一个团队的人进行数据库的增加操作,我的操作就是先查询一遍数据库,看看还有那些数据需要插入,然后我后面插入的时候也是看第一遍查询的结果吗,这样我一个人做的话,是不会出现什么问题的,但是如果跟我同一个团队的人也在执行同样的操作的话,他插入了我将要插入的数据,但是我还是按照第一编查询的结果来,那么这个数据就不能成功插入,我再查询,还是第一遍的结果,我说这条数据我没插入啊,为什么插入不进去呢?这就是幻读的问题。

事务隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
串行化×××

随着隔离级别的提高,效率也会降低。

Spring 事务隔离级别

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

  1. Isolation.DEFAULT:以连接的数据库事务隔离级别为主
  2. Isolation.READ_UNCOMMITTED:读未提交,对应SQL标准的 READ UNCOMMIT
  3. Isolation.READ_COMMITTED:读已提交,对应SQL标准的 READ COMMIT
  4. Isolation.REPEATABLE_READ:可重复读,对应SQL标准的REPEATABLE READ
  5. Isolation.SERIALIZABLE:串行化,对应SQL标准的SERIALIZABLE

在这里插入图片描述

Spring 中隔离级别的配置需要配置 @Transactional 注解的 isolation 属性:

@Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
Spring 事务传播机制

什么是事务传播机制?

事务传播机制是指当一个事务(父事务)调用另一个事务(子事务)的方法时,子事务如何传播的事务处理机制。它主要解决的是在多个事务方法相互调用时,如何决定使用哪个事务上下文以及如何管理这些事务的执行顺序和隔离级别。

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

在这里插入图片描述
而事务传播机制解决的是一个事务在多个节点(方法)中传递的问题

在这里插入图片描述
Spring 中的事务传播机制有7种:

  1. Propagation.REQUIRED:默认的事务传播机制。如果当前存在事务,则加入该事务;如果没有事务,则创建一个新事务
  2. Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果不存在事务,则以非事务的方式继续运行
  3. Propagation.MANDATORY:强制性。如果当前存在事务,则加入该事务,如果不存在,则抛出异常
  4. Propagation.REQUIRES_NEW:创建一个新的事务。如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都是新开始自己的事务,且开启的事务相互独立,互不干扰
  5. Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起(不用)
  6. Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
  7. Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 Propagation.REQUIRED

在这里插入图片描述

对于上面的事务传播机制,我这里主要为大家说明两种:

  1. REQUIRED(默认值)
  2. REQUIRES_NEW

这里我们在 controller 层和 service 层都加上这个注解 @Transactional(propagation = Propagation.REQUIRED)

@RequestMapping("/trans")
@RestController
public class TransactionalController {
    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private LogInfoService logInfoService;

    @Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    @RequestMapping("/registry")
    public String registry(String name, String password) throws IOException {
        userInfoService.registryUser(name,password);
        logInfoService.insertLog(name,"注册");
        return "注册成功";
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在其中一个事务中制造异常:

@Transactional(propagation = Propagation.REQUIRED)
public void registryUser(String name, String password) {
    userInfoMapper.insert(name, password);
    System.out.println(10/0);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,当事务传播机制为 Propagation.REQUIRED 的时候,当其中任何一个事务出现异常的时候,整个事务都会执行事务回滚的操作。

再来看看 Propagation.REQUIRED_NEW 隔离级别:

@Transactional(propagation = Propagation.REQUIRES_NEW)

还是 userInfoService 中抛出异常:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到 Propagation.REQUIRED_NEW 隔离级别中的事务都是相互独立的,互不影响。

将隔离级别改为 NEVER

在这里插入图片描述
当隔离级别为 NEVER 的时候,如果当前存在事务,就会直接报错。

NESTES 隔离级别

在这里插入图片描述
使用嵌套 NESTED 隔离级别,当其中一个事务抛出异常之后,所有事务都会回滚。

但是这样不就和 REQUIRED 隔离级别是一样的吗?这样看确实一样,但是还是有区别的:

我们将出现错误的事务单独进行回滚:

@Transactional(propagation = Propagation.NESTED)
public void registryUser(String name, String password)throws RuntimeException {
    userInfoMapper.insert(name, password);
    try {
        System.out.println(10/0);
    }catch (Exception e) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后将隔离级别改为 REQUIRED:

在这里插入图片描述
整个事务都回滚了。

所以 REQUIRED 和 NESTED 隔离界别的区别:

  • 整个事务如果都执行成功,二者的结果是一样的
  • 如果事务一部分执行成功,REQUIRED 加入事务会导致整个事务回滚,NESTED 嵌套事务可以实现局部回滚,不会影响上一个方法的执行结果

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

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

相关文章

最新的 Ivanti SSRF 零日漏洞正在被大规模利用

Bleeping Computer 网站消息,安全研究员发现 Ivanti Connect Secure 和 Ivanti Policy Secure 服务器端请求伪造 (SSRF) 漏洞(CVE-2024-21893 )正在被多个威胁攻击者大规模利用。 2024 年 1 月 31 日,Ivanti 首次就网关 SAML 组件…

Vivado-IP核

Vivado-IP核 主程序 timescale 1ns / 1ps ////module ip_clk_wiz(input sys_clk,input sys_rst_n,output clk_out1,output clk_out2,output clk_out3,output clk_out4,output locked);clk_wiz_0 instance_name(// Clock out ports.clk_out1(clk_out1), // output clk_out…

java设计模式- 建造者模式

一 需求以及实现方式 1.1 需求描述 我们要创建一个表示汽车的复杂对象,汽车包含发动机、轮胎和座椅等部分。用传统方式创建,代码如下 1.2 传统实现方式 1.抽象类 public abstract class BuildCarAbstaract {//引擎public abstract void buildEng…

OpenGL 入门(十)— 光照系统

光照系统 前言平行光点光源衰减衰减的实现 聚光平滑/软化边缘 多光源 前言 介绍三种光源类型:平行光(Directional Light)、点光源(Point Light)、聚光灯(Spot Light)。 平行光(Directional Light):只有一…

【力扣】整数反转,判断是否溢出的数学解法

整数反转原题地址 方法一:数学 反转整数 如何反转一个整数呢?考虑整数操作的3个技巧: xmod10可以取出x的最低位,如x123,xmod103。x/10可以去掉x的最低位,如x123,x/10,x12。xx*10…

C# CAD交互界面-自定义面板集(四)

运行环境 vs2022 c# cad2016 调试成功 一、程序说明 创建自定义面板集(PaletteSet)的C#命令方法实现。该方法名为CreatePalette,当在AutoCAD环境中调用此命令时,会执行以下操作: 获取AutoCAD主应用对象&#xff1…

docer compose部署simple-docker

简介 一个看似简陋但是功能足够用的docker管理工具 安装 创建目录 mkdir -p /opt/simple-docker cd /opt/simple-docker 创建并启动容器 编写docker-compose.yml文件,内容如下 version: 3 services: redis: image: redis:latest restart: always web: image: registry.cn-…

APP攻防-资产收集篇FridaHOOKXposed证书提取单向双向检验抓包mobsf

知识点 1、单向校验-XP框架&Frida&HOOK 2、双向校验-Frida&HOOK&导入证书 一、演示案例-APP-综合分析-Mobexler&MobSF识别 mobsf 移动安全框架 (MobSF) 是一种自动化的一体化移动应用程序 (Android/iOS/Windows) 渗透测试、恶意软件分析和安全评估框架…

Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器

本工作簿演示了 Elasticsearch 的自查询检索器将非结构化查询转换为结构化查询的示例,我们将其用于 BM25 示例。 在这个例子中: 我们将摄取 LangChain 之外的电影样本数据集自定义 ElasticsearchStore 中的检索策略以仅使用 BM25使用自查询检索将问题转…

Fate-Serving推理服务源码解读

https://fate-serving.readthedocs.io/en/develop/?queryguest 什么是Fate-Serving fate-serving是FATE的在线部分,在使用FATE进行联邦建模完成之后,可以使用fate-serving进行包括单笔预测、多笔预测以及多host预测在内的在线联合预测。 模型的初始化流…

用友U8 Cloud ReportDetailDataQuery SQL注入漏洞复现(QVD-2023-47860)

0x01 产品简介 用友U8 Cloud 提供企业级云ERP整体解决方案,全面支持多组织业务协同,实现企业互联网资源连接。 U8 Cloud 亦是亚太地区成长型企业最广泛采用的云解决方案。 0x02 漏洞概述 用友U8 cloud ReportDetailDataQuery 接口处存在SQL注入漏洞,攻击者未经授权可以访…

adb push 将电脑中的文件传输到安卓开发板

1. adb remount 重新挂载设备的文件系统,以便可以对设备进行读写操作,通常情况下,安卓开发板在连接到计算机后,设备的文件系统会被挂载为只读文件系统,重新挂载后变成可读可写权限 C:\Users\Administrator>adb re…

C++ 动态规划 区间DP 石子合并

设有 N 堆石子排成一排,其编号为 1,2,3,…,N 。 每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。 每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻…

第三讲 多重背包问题①——转化

【题目来源】AcWing 4. 多重背包问题 I 【题意分析】和完全背包问题类似,但是区别在于每一种物品的数量是有限的。 【解决方法】 1.转化为 0 / 1 0/1 0/1 背包问题 因为每一种物品数量有限,所以将每个物品看作单独的种类,可转化为 0 / 1 0/…

Spring Data Envers 数据审计实战2 - 自定义监听程序扩展审计字段及字段值

上篇讲述了如何在Spring项目中集成Spring Data Envers做数据审计和历史版本查看功能。 之前演示的是业务表中已有的字段进行审计,那么如果我们想扩展审计字段呢? 比如目前对员工表加入了Audited审计,员工表有个字段为dept_id,为…

JVM 性能调优 - 参数基础(2)

查看 JDK 版本 $ java -version java version "1.8.0_151" Java(TM) SE Runtime Environment (build 1.8.0_151-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode) 查看 Java 帮助文档 $ java -help 用法: java [-options] class [args...] …

C语言实现memcpy、memmove库函数

目录 引言一、库函数介绍二、库函数详解三、源码实现1.memcpy源码实现2.memmove源码实现 四、测试1.memcpy函数2.memmove函数 五、源码1.memcpy源码2.memmove源码 六、参考文献 引言 关于memcpy和memmove这两个函数,不论是算法竞赛还是找工作面试笔试,对…

如何正确理解和获取S参数

S参数是网络参数,定义了反射波和入射波之间的关系,给定频率的S参数矩阵指定端口反射波b的矢量相对于端口入射波a的矢量,如下所示: bS∙a 在此基础上,如下图所示,为一个常见的双端口网络拓扑图:…

一文简介Maven初级使用

一.概述 Maven是专门用于管理和构建Java项目的工具,它的主要功能有: 提供了一套标准化的项目结构提供了一套标准化的项目构建流程(编译,测试,打包,发布)提供了一套依赖管理机制 一方面&…

跟着pink老师前端入门教程-day19

一、移动WEB开发之流式布局 1、 移动端基础 1.1 浏览器现状 PC端常见浏览器:360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 移动端常见浏览器:UC浏览器,QQ浏览器,欧朋浏览器&#xff0…