MyBatis3源码深度解析(七)JDBC单连接事务

文章目录

    • 前言
    • 2.7 JDBC单连接事务
      • 2.7.1 事务的开启与提交
      • 2.7.2 事务隔离级别
        • 2.7.2.1 并发访问问题
          • (1)脏读
          • (2)不可重复读
          • (3)幻读
        • 2.7.2.2 事务隔离级别
          • (1)TRANSACTION_NONE:不支持事务
          • (2)TRANSACTION_READ_UNCOMMITTED:读未提交
          • (3)TRANSACTION_READ_COMMITTED:读提交
          • (4)TRANSACTION_REPEATABLE_READ:可重复读
          • (5)TRANSACTION_SERIALIZABLE:串行化
      • 2.7.3 事务中的保存点
    • 2.8 小结

前言

DatabaseMetaData接口中有一个supportsTransactions()方法,用于判断当前数据源是否支持事务。

事务用于提供数据完整性、正确的应用程序语义和并发访问的数据一致性。所有遵循JDBC规范的驱动程序都需要提供事务支持。

本节研究JDBC中的单连接事务。

2.7 JDBC单连接事务

2.7.1 事务的开启与提交

在JDBC API中,没有对应的方法显式地开启事务,因此何时开启一个新的事务是由JDBC驱动程序或数据库隐式决定的

通常情况下,当SQL语句需要开启事务但目前还没有事务时,会自动地开启一个新的事务。

对于什么时候提交或回滚事务,Connection接口提供了setAutoCommit(boolean autoCommit)commit()rollback()等方法来进行控制。

  1. setAutoCommit(boolean autoCommit)方法用于设置事务是否自动提交,默认情况下事务自动提交是开启的,每个SQL语句执行完毕后会自动地提交事务。
  2. 如果使用setAutoCommit(boolean autoCommit)方法禁用了事务的自动提交,则需要显式地调用commit()方法提交事务,或者调用rollback()方法回滚事务。

禁用事务自动提交一般适用于需要将多个SQL语句作为一个事务提交或者事务由应用服务器管理的情况。

2.7.2 事务隔离级别

事务隔离级别用于表示事务中对数据的操作对其他事务的“可见性”,主要用于解决数据并发访问中的可能会出现的问题,且会直接影响到并发访问的效率。

Connection接口中提供了一个setTransactionIsolation(int level)方法,用于设置当前驱动程序的事务隔离级别。

2.7.2.1 并发访问问题
(1)脏读

脏读是指在一个事务中读取到另一个事务中未提交的数据。例如,A事务修改了一条数据,但是未提交修改,此时A事务对数据的修改对其他事务是可见的,因此B事务中能够读取A事务未提交的修改。一旦A事务回滚,B事务中读取的就是不正确的数据。

下面用一个简单例子来解释。

在数据库中插入一条数据:

在数据库中插入一条数据
编写A事务和B事务的测试代码:

@Test
public void testA() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交(下文解释)connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 读取一条记录String sql = "select * from user where id = 1";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);resultSet = statement.executeQuery(sql);resultSet.next();System.out.println("A事务读取的用户信息:" + new User(resultSet).toString());// 修改这条记录resultSet.updateString("name", "孙悟空");resultSet.updateRow();System.out.println("A事务修改后的用户信息:" + new User(resultSet).toString());// 此处打一个断点 ...// 回滚事务connection.rollback();} catch (Exception e) {e.printStackTrace();} finally {DbUtils.close(resultSet, statement, connection);}
}@Test
public void testB() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 读取一条记录String sql = "select * from user where id = 1";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);resultSet = statement.executeQuery(sql);resultSet.next();System.out.println("B事务读取的用户信息:" + new User(resultSet).toString());// 此处打一个断点 ...// 提交事务connection.commit();} catch (Exception e) {e.printStackTrace();} finally {DbUtils.close(resultSet, statement, connection);}
}

下面开始模拟脏读产生的过程:

  1. 以Debug方式执行A事务中的查询记录、修改记录操作,停到断点处,控制台打印修改前和修改后的用户数据;

  1. 以Debug方式执行B事务中的查询记录操作,停到断点处,控制台打印查询出来的用户数据,确实是A事务修改后但未提交的用户数据;

  1. 继续执行A事务,回滚修改操作,但B事务已经拿到了A事务修改后的用户数据,如果B事务对修改后的数据进一步处理,就是不符合要求的,这就产生脏读。
(2)不可重复读

不可重复读是指在同一个事务中,对于同一份数据的多次读取可能返回不同的结果。例如,A事务读取了一行数据,但此时B事务中修改了该行数据,A事务中再次读取该行数据将得到不同的结果。

下面用一个简单例子来解释。

在数据库中只有一条数据:

编写A事务和B事务的测试代码:

@Test
public void testA() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 读取一条记录String sql = "select * from user where id = 1";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);resultSet = statement.executeQuery(sql);resultSet.next();System.out.println("A事务首次读取的用户信息:" + new User(resultSet).toString());// 此处打一个断点 ...// 再次读取记录resultSet = statement.executeQuery(sql);resultSet.next();System.out.println("A事务再次读取的用户信息:" + new User(resultSet).toString());// 提交事务connection.commit();} catch (Exception e) {e.printStackTrace();} finally {DbUtils.close(resultSet, statement, connection);}
}@Test
public void testB() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 读取一条记录String sql = "select * from user where id = 1";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);resultSet = statement.executeQuery(sql);resultSet.next();System.out.println("B事务读取的用户信息:" + new User(resultSet).toString());// 修改这条记录resultSet.updateString("name", "孙悟空");resultSet.updateRow();System.out.println("B事务修改后的用户信息:" + new User(resultSet).toString());// 提交事务connection.commit();} catch (Exception e) {e.printStackTrace();} finally {DbUtils.close(resultSet, statement, connection);}
}

下面开始模拟不可重复读产生的过程:

  1. 以Debug方式执行A事务中的首次查询记录操作,停到断点处,控制台打印首次查询的用户数据;

  1. 直接执行B事务中的查询记录、修改记录操作,控制台打印处理结果,此时数据库记录也已被修改;


  1. 继续执行A事务,再次以相同的SQL查询用户数据,发现查询的数据是修改后的,这就产生了不可重复读的问题。

(3)幻读

幻读发生在多个事务同时读取和修改数据时。例如,当A事务正在读取一系列数据时,B事务可能会插入一些新的数据,然后提交事务。当A事务再次查询相同的记录集时,它可能会发现一些原本不存在的记录,这会导致数据的不一致性,给用户造成幻觉。

幻读和不可重复读的区别在于,不可重复读侧重于已存在数据的更改,而幻读侧重于新增数据的插入。

下面用一个简单例子来解释。

在数据库中只有一条数据:

编写A事务和B事务的测试代码:

@Test
public void testA() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 查询记录集String sql = "select * from user";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);resultSet = statement.executeQuery(sql);System.out.println("A事务首次读取的用户信息有:");while (resultSet.next()) {System.out.println(new User(resultSet).toString());}System.out.println("-----------------------");// 此处打一个断点 ...// 再次查询记录集resultSet = statement.executeQuery(sql);System.out.println("A事务再次读取的用户信息有:");while (resultSet.next()) {System.out.println(new User(resultSet).toString());}// 提交事务connection.commit();} catch (Exception e) {e.printStackTrace();} finally {// 关闭资源DbUtils.close(resultSet, statement, connection);}
}@Test
public void testB() {Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {connection = DbUtils.getConnection();// 关闭事务自动提交connection.setAutoCommit(false);// 设置事务隔离级别为:读未提交connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);// 插入一条记录String sql = "INSERT INTO USER (NAME, age, phone, birthday) VALUES('user1', 18, '18705464523', '2000-02-21 10:24:30');";statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);statement.executeUpdate(sql);// 提交事务connection.commit();} catch (Exception e) {e.printStackTrace();} finally {// 关闭资源DbUtils.close(resultSet, statement, connection);}
}

下面开始模拟幻读产生的过程:

  1. 以Debug方式执行A事务中的首次查询记录集操作,停到断点处,控制台打印首次查询的用户数据;

  1. 直接执行B事务中的插入记录操作,控制台打印处理结果,此时数据库记录也增加了一条;

  1. 继续执行A事务,再次以相同的SQL查询用户数据集,发现查询的数据还包括B事务新增的,这就产生了幻读的问题。

2.7.2.2 事务隔离级别

JDBC遵循SQL:2003规范,定义了5种事务隔离级别:

(1)TRANSACTION_NONE:不支持事务
(2)TRANSACTION_READ_UNCOMMITTED:读未提交

这种事务隔离级别允许某一事务读取另一事务未提交更改的数据,这意味着可能会出现脏读、不可重复读、幻读现象。

【2.7.2.1 并发访问问题】的三个案例均将事务隔离级别设置为“读未提交”,经过实际测试,确实会发生脏读、不可重复读、幻读现象。

(3)TRANSACTION_READ_COMMITTED:读提交

这种事务隔离级别表示在某一事务中进行任何数据的更改,在提交之前对其他事务都是不可见的,这样可以防止脏读,但不能解决不可重复读、幻读问题。

这是MySQL驱动程序默认的事务隔离级别。

下面继续使用【2.7.2.1 并发访问问题】中的三个案例进行测试。

首先手动将事务隔离级别设置为TRANSACTION_READ_COMMITTED读提交,其余代码保持不变。

// 设置事务隔离级别为:读提交
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
  • 测试脏读问题:已解决
  1. 以Debug方式执行A事务中的查询记录、修改记录操作,停到断点处,控制台打印修改前和修改后的用户数据;

  1. 以Debug方式执行B事务中的查询记录操作,停到断点处,控制台打印查询出来的用户数据,确实是原来的数据,而不是A事务修改后但未提交的用户数据

  1. 继续执行A事务,回滚修改操作,但B事务拿到的是A事务修改前的用户数据,符合要求,脏读问题已被解决。
  • 测试不可重复读问题:未解决

  • 测试幻读问题:未解决

(4)TRANSACTION_REPEATABLE_READ:可重复读

这种事务隔离级别表示在某一事务中对同一数据进行多次读取时,可以得到相同的结果,并且其他事务插入数据的操作对该事务不可见,这样可以防止脏读、不可重复读,但不能解决幻读问题;

下面继续使用【2.7.2.1 并发访问问题】中的三个案例进行测试。

首先手动将事务隔离级别设置为TRANSACTION_REPEATABLE_READ可重复读,其余代码保持不变。

// 设置事务隔离级别为:可重复读
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
  • 测试脏读问题:已解决

  • 测试不可重复读问题:已解决

  1. 以Debug方式执行A事务中的首次查询记录操作,停到断点处,控制台打印首次查询的用户数据;

  1. 直接执行B事务中的查询记录、修改记录操作,控制台打印处理结果,此时记录已被修改;

  1. 继续执行A事务,再次以相同的SQL查询用户数据,发现查询的数据是修改前的,这就解决了不可重复读的问题。

  • 测试幻读问题:未解决
(5)TRANSACTION_SERIALIZABLE:串行化

这种事务隔离级别是最高的事务隔离级别,保证数据的一致性和完整性,可以防止脏读、不可重复读,、幻读问题,但是并发性较差。

下面继续使用【2.7.2.1 并发访问问题】中的三个案例进行测试。

首先手动将事务隔离级别设置为TRANSACTION_SERIALIZABLE串行化,其余代码保持不变。

// 设置事务隔离级别为:串行化
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
  • 测试脏读问题:已解决

  • 测试不可重复读问题:已解决

  • 测试幻读问题:已解决

  1. 以Debug方式执行A事务中的首次查询记录集操作,停到断点处,控制台打印首次查询的用户数据;

  1. 直接执行B事务中的插入记录操作,发现报错,无法打开新的事务。

  1. 继续执行A事务,再次以相同的SQL查询用户数据集,发现查询的数据是一样的,这就解决了幻读的问题。

  1. A事务提交后,再次执行B事务,发现可以成功执行,说明串行化等级下一次只能打开一个事务。

2.7.3 事务中的保存点

保存点是指通过事务中标记的一个中间点来对事务进行更细粒度的控制,一旦设置保存点,事务就可以归滚到保存点,而不影响保存点之前的操作。

DatabaseMetaData接口提供了supportsSavepoints()方法用于判断JDBC驱动程序是否支持保存点。

Connection接口提供了``setSavepoint()```方法用于在当前事务中设置保存点。如果该方法在事务外中调用,则会在该方法调用处开启一个新的事务。

该方法的返回值是一个Savepoint对象,该对象可作为COnnection接口的rollback()方法的参数,用于回滚到对应的保存点。

示例代码如下:

// ......
// 关闭事务自动提交
connection.setAutoCommit(false);
// 读取一条记录
String sql = "select * from user where id = 1";
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
resultSet = statement.executeQuery(sql);
resultSet.next();
System.out.println("第一次读取的用户信息:" + new User(resultSet).toString());
// 第一次修改这条记录
resultSet.updateString("name", "孙悟空-修改1");
resultSet.updateRow();
System.out.println("第一次修改后的用户信息:" + new User(resultSet).toString());
// 设置保存点
Savepoint savepoint = connection.setSavepoint();
// 第二次修改这条记录
resultSet.updateString("name", "孙悟空-修改2");
resultSet.updateRow();
System.out.println("第二次修改后的用户信息:" + new User(resultSet).toString());
// 回滚到保存点
connection.rollback(savepoint);
// 再次读取这条记录
// 读取一条记录
resultSet = statement.executeQuery(sql);
resultSet.next();
System.out.println("第二次读取的用户信息:" + new User(resultSet).toString());
// 提交事务
connection.commit();
// ......

控制台打印执行结果:

第一次读取的用户信息:User{id=1, name='黑风怪', age=18, phone='18705464523', birthday=2000-02-21}
第一次修改后的用户信息:User{id=1, name='孙悟空-修改1', age=18, phone='18705464523', birthday=2000-02-21}
第二次修改后的用户信息:User{id=1, name='孙悟空-修改2', age=18, phone='18705464523', birthday=2000-02-21}
第二次读取的用户信息:User{id=1, name='孙悟空-修改1', age=18, phone='18705464523', birthday=2000-02-21}

在示例代码中,依次进行读取记录→第一次修改→设置保存点→第二次修改→回滚到保存点→再次读取记录→提交事务,第二次读取的结果恰好就是第一次修改后的结果,说明确实回滚到了保存点的位置。

保存点创建后,可以被手动释放。Connection接口提供了releaseSavepoint()方法,接收一个Savepoint对象为参数,用于释放保存点。保存点被释放后,如果试图通过rollback()方法回滚到保存点,则会抛出SQLException异常。

事务中创建的保存点在事务提交或回滚之后会自动释放,事务回滚到某一保存点之后,该保存点之后的保存点将会自动释放。

2.8 小结

第2章到此就梳理完毕了,本章的主题是:JDBC规范。回顾一下本章的梳理的内容:

(二)JDBC API简介
(三)Connection
(四)Statement
(五)ResultSet
(六)DatabaseMetaData
(七)JDBC单连接事务

更多内容请查阅分类专栏:MyBatis3源码深度解析

第3章主要梳理:MyBatis常用工具类。主要内容包括:

  • 使用SQL类生成语句;
  • 使用ScriptRunner执行脚本;
  • 使用SqlRunner操作数据库;
  • MetaObject详解;
  • MetaClass详解;
  • ObjectFactory详解;
  • ProxyFactory详解。

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

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

相关文章

BJFU|计算机网络期末复习考前速记

整理了一些重要名词的定义与概念,适合在考前几个小时过几次加深印象,可以更好应对选填与简答的题型。 互联网的定义:广义观点-远程信息处理进一步达到资源共享;资源共享观点-以相互共享资源的方式互联起来的自治计算机系统的集合…

百度信息流

计划: 流量选择 - 四个维度: 百度信息流 ; 整合了百度APP、WAP、PC各频道信息流和内容详情页的流量资源,广告和信息流内容资讯穿插展现;适合所有产品呢 好看视频; 汇集海量优质的视频内容,通过智能推荐算法为用户推送最适合的视频广告,视频广告在列表页有声…

【故障分类】基于注意力机制的卷积神经网络结合双向长短记忆神经网络CNN-BiLSTM-attention实现数据分类附matlab代码

摘要: 本文详细介绍了一种基于注意力机制的卷积神经网络(CNN)结合双向长短记忆神经网络(BiLSTM)实现数据分类的方法,并给出了详细的Matlab实现代码。本文首先概述了CNN、BiLSTM和注意力机制的基本原理,然后阐述了整体网络结构的设计思路&…

ChatGPT 串接到 Discord - 团队协作好助理

ChatGPT 串接到 Discord - 团队协作好助理 ChatGPT 是由 OpenAI 开发的一个强大的语言模型,本篇文章教你如何串接 Discord Bot ,协助团队在工作上更加高效并促进沟通与协作。使 ChatGPT 发挥出最大的功效,进一步提升工作效率和团队协作能力。…

Redis 内存的优化

目录 前言 Redis 的内存碎片问题 判断Redis 内存碎片 如何清理内存碎片? 前言 我想讲一下怎么提高Redis 内存的利用率,redis 的数据是保存在内存中。对内存的利用率低,意味着存的数据很少,并不意味着就没有内存了&#xff0c…

【解读】OWASP大语言模型应用程序十大风险

OWASP大型语言模型应用程序前十名项目旨在教育开发人员、设计师、架构师、经理和组织在部署和管理大型语言模型(LLM)时的潜在安全风险。该项目提供了LLM应用程序中常见的十大最关键漏洞的列表,强调了它们的潜在影响、易利用性和在现实应用程序…

利用华为CodeArts持续交付项目演示流程

软件开发生产线(CodeArts)是面向开发者提供的一站式云端平台,即开即用,随时随地在云端交付软件全生命周期,覆盖需求下发、代码提交、代码检查、代码编译、验证、部署、发布,打通软件交付的完整路径&#xf…

力扣---腐烂的橘子

题目&#xff1a; bfs思路&#xff1a; 感觉bfs还是很容易想到的&#xff0c;首先定义一个双端队列&#xff08;队列也是可以的~&#xff09;&#xff0c;如果值为2&#xff0c;则入队列&#xff0c;我这里将队列中的元素定义为pair<int,int>。第一个int记录在数组中的位…

3.8IO作业

1&#xff1a;编写链表&#xff0c;链表里面随便搞点数据 使用 fprintf 将链表中所有的数据&#xff0c;保存到文件中 使用 fscanf 读取文件中的数据&#xff0c;写入链表中&#xff0c;实现&#xff0c;当按 ctrl c的时候&#xff0c;保存链表 #include <stdio.h> #in…

day15_集合_ArrayList

今日内容 零、 复习昨日 一、集合框架体系 二、Collection 三、泛型 四、迭代 五、List(ArrayList、LinkedList) 零、 复习昨日 日期解析的方法签名(字符串–>日期) Date parse(String s) 日期格式化的方法签名(日期–>字符串) String format(Date date) 运行时异常有哪些…

19、电源管理入门之微内核中的电源管理

目录 1. QNX电源管理框架 2. QNX客户端API库 3. QNX代码分析 4. Fuchsia中的电源管理 5. Minix中的电源管理 6. Harmony OS中的电源管理 之前介绍的电源管理机制基本都是在Linux中实现的,可以看到很复杂,各种框架,明明一个操作非要转来转去,而且在内核里面实现,跟内…

【HarmonyOS】ArkTS-联合类型

目录 联合类型实例 联合类型 联合类型是一种灵活的数据类型&#xff0c;它修饰的变量可以存储不同类型的数据。 语法&#xff1a;let 变量: 类型1 | 类型2 | 类型3 值 基于联合类型&#xff0c;变量可存不同类型数据 实例 // 需求&#xff1a;定义一个变量&#xff0c;存放…

Spring web开发(入门)

1、我们在执行程序时&#xff0c;运行的需要是这个界面 2、简单的web接口&#xff08;127.0.0.1表示本机IP&#xff09; package com.example.demo;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestCont…

srlua打包(Lua 5.4.6)

资源 Lua - Joe DFs Builds 或者在文章附加资源下载。 使用方法 在当前文件夹打开文件夹&#xff0c;使用cmd。srglue.exe srlua.exe in.lua out.exe 或 srglue srlua.exe in.lua out.exe in.lua&#xff1a;指用进行打包的lua文件。out.exe&#xff1a;指输出的exe文件的…

【OD】算法二

开源项目热度榜单 某个开源社区希望将最近热度比较高的开源项目出一个榜单&#xff0c;推荐给社区里面的开发者。对于每个开源项目&#xff0c;开发者可以进行关注(watch)、收藏(star)、fork、提issue、提交合并请求(MR)等。 数据库里面统计了每个开源项目关注、收藏、fork、…

垃圾回收:JavaScript内存管理的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Java算法-力扣leetcode-55. 跳跃游戏

55. 跳跃游戏 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&a…

ChatGPT 控制机器人的基本框架

过去的一年&#xff0c;OpenAI的chatGPT将自然语言的大型语言模型&#xff08;LLM&#xff09;推向了公众的视野&#xff0c;人工智能AI如一夜春风吹遍了巴黎&#xff0c;全世界都为AI而疯狂。 OpenAI ChatGPT是一个使用人类反馈进行微调的预训练生成文本模型。不像以前的模型主…

Spring Cloud Gateway自定义过滤器

自定义全局过滤器 相关面试题&#xff1a;统计接口调用耗时&#xff0c;如何落地&#xff0c;谈谈设计思路&#xff1f; 自定义统计接口耗时的全局过滤器 https://docs.spring.io/spring-cloud-gateway/docs/4.0.9/reference/html/#gateway-combined-global-filter-and-gatewa…

python中def简介及用法

什么是def&#xff1f; def是python中的一个关键字&#xff0c;它用于定义一个函数。函数是一段具有特定功能的代码&#xff0c;可以被重复调用&#xff0c;从而提高代码的复用性和可读性。 如何使用def&#xff1f; def的基本语法如下&#xff1a; def 函数名(参数列表):#…