事务隔离级别是怎么实现的?

news2024/11/26 15:29:48

事务有哪些特性?

事务是由 MySQL 的引擎实现的,我们常见的 InnoDB引擎时支持事务的。

不过并不是所有的引擎都支持事务,比如 MySQL原生的 MyISAM 引擎就不支持事务,正因为如此,大多数MySQL的引擎都是用 InnoDB。

事务的四个特性:

  • 原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样
  • 一致性:是指事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态。比如从A账户转账 100元到B账户。一致性要求上述转账后 AB账户的总值是不变的。
  • 隔离性:数据库允许多个并行事务同时对数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,因为多个事务同时使用相同的数据时,不会相互干扰,每个事务都有一个完整的数据空间,对其他并发事务是隔离的。
  • 持久性:事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。

InnoDB 引擎通过什么来保证事务的这四个特性?

  • 持久性是通过 redo log (重做日志)来保证的
  • 原子性是通过 undo log (回滚日志)来保证的
  • 隔离性是通过 MVCC (多版本并发控制)或锁机制来保证的
  • 一致性是通过持久性 + 原子性 + 隔离性来保证的

并行事务会引发什么问题?

MySQL服务端是允许多个客户端连接的,这意味着 MySQL 会出现同时处理多个事务的情况。

那么在同时处理多个事务的时候,就可能出现脏读、不可重复读、幻读的问题。

脏读

如果一个事务 [读到] 了另一个 [未提交事务修改过的数据] ,就意味着发生了 [脏读] 现象

eg:

假设有 A 和 B这个事务同时在处理,事务 A 先开始从数据库中读取余额数据,然后再执行更新操作,如果此时事务 A 还没有提交事务,而此时正好事务 B 也从数据库中读取余额数据,那么事务 B 读取到的余额数据是刚才事务 A 更新后的数据,即使没有提交事务。

因为事务 A 是还没提交事务的,也就是它随时可能发生回滚操作,如果在上面这种情况事务A发生了回滚,那么事务 B 刚才得到的数据就是过期的数据,这种现象被称为脏读

不可重复读

一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,这就意味着发生了 [不可重复度] 现象

eg:

假设有 A 和 B 两个事务同时在处理,事务 A 先开始从数据库中读取余额数据,然后继续执行代码处理逻辑,在这过程中如果事务 B 更新了这条数据,并提交了事务,那么当事务 A 再次读取该数据时,就会发现前后两次读取的数据是不一致的,这种现象就被称为不可重复读

幻读

在一个事务内多次查询某个符合条件的 [记录数量] , 如果出现前后两次查询到的记录数量不一样的情况,这就意味着发生了 幻读 现象

eg:

假设有 A 和 B 两个事务同时在处理,事务 A 先开始从数据库查询账户余额大于 100 万的记录,发现共有 5 条 ,然后事务 B也按照相同的搜索条件也是查询出了 5 条记录。

接下来,事务 A 插入了一条余额超过 100 万的记录,并提交了事务,此时数据库超过 100 万余额的账号个数就变为 6 。

然后事务 B 再次查询账户余额大于 100 万的记录,此时查询到的记录数量有 6 条,发现和前一次读到的记录数量不一样了。就感觉发生了幻觉一样,这种现象就被称为 幻读


事务的隔离级别有哪些?

前面提到,当多个事务并发执行时可能会遇到 [脏读、不可重复读、幻读] 的现象,这些现象会对事务的一致性产生不同程度的影响。

  • 脏读:读到其他事务未提交的数据
  • 不可重复读:前后读取的数据不一致
  • 幻读:前后读取的记录数量不一致

三个现象的严重性排序如下:

SQL 标准提出了四种隔离级别来规避这些现象,隔离级别越高,性能效率就越低,这四个隔离级别如下:

  • 读未提交:指一个事务还没提交时,它做的变更就能被其他事务看到
  • 读提交:指一个事务提交之后,它做的变更才能被其他事务看到
  • 可重复读:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据时一致的,MySQL InnoDB 引擎的默认隔离级别
  • 串行化:会对数据加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

按照隔离水平高低排序:

针对不同的隔离级别,并发事务可能发生的现象也会不同。

也就是说:

  • 在 [读未提交] 的隔离级别下,可能发生脏读、不可重复度和幻读的现象
  • 在 [读提交] 的隔离级别下,可能会发生不可重复读和幻读的现象
  • 在 [可重复读] 的隔离级别下,可能会发生幻读的现象
  • 在 [串行化] 的隔离级别下,脏读、不可重复读和幻读现象都不可能会发生

所以,要解决脏读现象,就要升级到 [读提交] 以上的隔离级别;要解决不可重复读现象,就要升级到 [可重复读] 的隔离级别,要解决幻读现象不建议将隔离级别升级到 [串行化] 。

不同的数据库厂商对 SQL 标准中规定的 4 种隔离级别的支持不一样,有的数据库只实现了其中的几种隔离级别,我们讨论的MySQL 虽然支持 4 种隔离级别,但是与 SQL 标准中规定的各级隔离级别允许发生的现象有些出入

MySQL 在 [可重复读] 的隔离级别下,可以很大程度上避免幻读现象的发生,所以MySQL 并不会使用 [串行化] 隔离级别来避免幻读现象的发生,因为使用 [串行化] 隔离级别会影响性能

MySQL InnoDB 引擎的默认级别虽然是 [可重复读] ,但是它很大程度上避免幻读现象,解决的方案有两种:

  • 针对快照读(普通select语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好避免了幻读。
  • 针对当前读(select ... for update等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当前执行 select ... for update语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这条插入语句就会被阻塞,无法成功插入,所以就很好避免了幻读问题。

举个例子说明这四种隔离级别,有一张用户余额表,里面有一条账户余额为 100万的记录。然后有两个并发的事务,事务 A 只负责查询余额,事务 B 则会将余额改成 220万,下面是按照时间顺序执行两个事务的行为:

在不同的隔离级别下,事务 A 执行过程中查询到的余额可能会不同:

  • 在 [读未提交] 隔离级别下,事务 B 修改余额后,虽然没有提交事务,但是此时的余额已经可以被事务 A 看见了,于是 事务 A 中的余额V1查询的值为 200万,余额V2、V3也是 200 万。
  • 在 [读提交] 隔离级别下,事务 B修改余额后,因为没有提交事务,所以事务 A 中余额 V1 的值还是 100万,等事务 B 提交完成后,最新的余额数据才能被事务 A 看见,因此 余额 V2、V3 都是 200 万
  • 在 [可重复度] 隔离级别下,事务 A 只能看见启动事务时的数据,所以余额V1、余额V2的值都是 100 万,当事务 A 提交事务后,就能看见最新的余额数据了,所以余额 V3的值是 200万
  • 在 [串行化] 隔离级别下,事务 B 在执行将余额 100 万修改为 200 万时,由于此前事务 A 执行了读操作,这样就发生了读写冲突,于是就会被锁住,直到事务 A提交后,事务B 才可以继续执行,所以从 A 的角度看,余额 V1、V2 的值是 100 万,余额 V3 的值是 200万。

四种隔离级别如何实现?

  • 对于 [读未提交] 隔离级别的事务来说,因为可以读到未提交事务修改的数据,所以直接读取到最新的数据就行了
  • 对于 [串行化] 隔离级别的事务来说,通过加读写锁的方式来避免并行访问
  • 对于 [读提交] 和 [可重复读] 隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,可以 把 Read View 理解为一个数据快照,就像照相机一样,定格某一时刻的风景。 [读提交] 隔离级别是在 [每个语句执行前] 都会生成一个 Read View。而 [可重复读] 隔离级别是 [启动事务时] 生成一个 Read View 。然后整个事务期间都在用这个 Read View.

PS:执行 [开始事务] 命令,并不意味着启动了事务。在 MySQL有两种开启事务的命令,分别是:

  • 第一种:begin/start transaction 命令
  • 第二种:start transaction with consistent snapshot 命令

这两种开启事务的命令,事务的启动时机是不同的:

  • 执行了· begin/start transaction 命令后,并不代表事务启动了。只有在执行这个命令后,执行了增删改查操作的SQL语句,才是事务真正启动的时机
  • 执行了 start transaction with consistent snapshot 命令,会马上启动事务

Read View 在 MVCC 里如何工作?

什么是 Read View ?

Read View 有四个重要的字段:

  • m_ids :指的是在创建 Read View时,当前数据库中 [活跃事务] 的事务id列表,注意是一个列表,“活跃事务”指的是,启动了但是还没提交的事务;
  • min_trx_id:指的是在创建 Read View 时,当前数据库中 [活跃事务] 中事务id 最小的事务,也就是 m_ids 的最小值
  • max_trx_id:这个并不是 m_ids 的最大值,而是创建 Read View 时当前数据库中应该给下一个事务的 id 值,也就是全局事务中 最大的事务id值 + 1;
  • creator_trx_id:指的是创建该 Read View 的事务的事务id

知道了 Read View 的字段,我们还需要了解聚簇索引记录中的两个隐藏列。

假设在账户余额表插入一条余额为 100 万的记录,然后把这两个隐藏列也画出来,该记录的整个示意图如下:

对于使用 InnoDB 存储引擎的数据库表,它的聚簇索引记录都包含下面两个隐藏列:

  • trx_id,当一个事务对某条聚簇索引进行改动时,就会把该事务的id记录在 trx_id 隐藏列里
  • roll_pointer,每次对某条聚簇索引记录进行改动时,就会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。

在创建 Read View 后,我们可以将记录中的 trx_id 划分为三种情况:

一个事务区访问记录的时候,除了自己的更新记录总是可见之外,还有几种情况:

  • 如果记录的 trx_id 值小于 Read View 中的 min_trx_id 值,表示这个版本的记录是创建 Read View 已经提交的事务生成的,所以该版本的记录对当前事务可见
  • 如果记录的 trx_id 值大于等于 Read View 中的 max_trx_id 值,表示这个版本的记录是在创建Read View 才启动的事务生成的,所以该版本的记录对当时事务不可见
  • 如果记录的 trx_id 值在 Read View 的 min_trx_id  max_trx_id 之间,需要判断 trx_id 是否在 m_ids 列表中:
    • 如果记录的 trx_id  m_ids 列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务不可见
    • 如果记录的 trx_id 不在 m_ids列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务可见

这种通过 [版本链] 来控制并发事务访问同一个记录的行为就叫MVCC(多版本并发控制)


可重复读是如何工作的?

可重复读隔离级别是启动事务时生成一个 Read View ,然后整个事务期间都在用这个 Read View

假设事务 A (事务id 为 51)启动后,紧接着事务B(事务id为52)也启动了,那这两个事务创建的Read View 如下:

事务 A 和 事务B 的 Read View 具体内容如下:

  • 在事务 A 的 Read View 中,它的事务 id 是 51,由于它是第一个启动的事务,所以此时活跃事务的事务 id 列表就只有 51,活跃事务的事务 id 列表中最小的事务 id 是 事务 A 本身,下一个事务 id 则是 52
  • 在事务 B 的Read View 中,它的事务 id 是 52 ,由于事务 A 是活跃的,所以此时活跃事务的事务 id 列为 51和52,活跃的事务 id 中最小的事务 id 是事务 A,下一个事务 id 应该是 53.

接着,在可重复读隔离级别下,事务 A 和事务 B 按顺序执行了以下操作:

  • 事务 B 读取账户余额,读到的余额是 100 万
  • 事务 A 将账户余额记录修改为 200 万,并没有提交事务
  • 事务 B 读取账户余额记录,读取到的余额还是 100 万
  • 事务 A 提交事务
  • 事务 B 读取账户余额记录,读到的余额依旧是 100 万

具体操作:

事务 B 第一次读取账户余额记录,在找到记录后,它会先看这条记录的 trx_id,此时发现 trx_id 为 50,比事务 B 的 Read view 中的 min_trx_id的值(51)小,这意味着修改这条记录的事务早已在事务 B 启动前提交过了,所以该版本的记录对事务 B 可见,也就是事务 B 可以获取到这条记录。

接着,事务 A 通过 update 语句将这条记录修改了(还未提交事务),将余额改成了 200 万,这时 MySQL 会记录相应的 undo log,并以链表的方式串联起来,形成 版本链,如下图:

可以在上图看到,由于事务 A 修改了记录,以前的记录juice变成了 旧版本的记录了,于是新记录的旧版本的记录通过链表的方式串起来

然后事务 B 第二次去读取该记录,发现这条记录的trx_id 为 51,在事务 B 的 Read View 的 min_trx_id 和 max_trx_id 之间,则需要判断 trx_id 值是否在 m_ids 范围内,判断结果是在的,那么说明这条记录是被未提交的事务修改的,这时事务 B 并不会读取这个版本的记录。而是沿着 undo log 链表往下找旧版本的记录,直到找到 trx_id [小于] 事务 B 的 Read View 中的 min_trx_id 值的第一条记录,所以事务 B 能读取到的是 trx_id 为 50 的记录,也就是余额为 100万的这条记录。

最后,当事务 A 提交事务后,由于隔离级别的 [可重复读] , 所以事务 B 再次被读取时,还是基于启动事务时创建的 Read View 来判断当前版本的记录是否可见。所以,即使事务 A 将余额改成了 200 万并提交了事务,事务 B 第三次读取记录时,读取到的记录都是 100 万这条记录

通过这种方式实现了,[可重复读] 隔离级别下在事务期间读到的记录都是事务启动前的记录。


读提交是如何工作的?

读提交隔离级别是在每次读取数据时,都会生成一个新的 Read View

这意味着,事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能在这期间另外一个事务修改了该记录,并提交了事务。

假设事务 A (事务id 为 51)启动后,紧接着 事务 B (事务id为 52)也启动了,接着按顺序执行了以下操作:

  • 事务 B 读取数据(创建Read View),账户余额为 100 万
  • 事务 A 修改数据(还没提交事务),将账户余额从 100万 修改为 200 万
  • 事务 B 读取数据(创建 Read View),账户余额为 100 万
  • 事务 A 提交事务
  • 事务 B 读取数据 (创建 Read View),账户余额为 200 万

具体如何做到的呢?前两次事务B读取数据时创建的 Read View 如下图:

为什么事务 B 第二次读取数据时,读取不到 事务 A (还未提交事务)修改的数据呢?

事务 B 在找到这条记录时,会看记录的 trx_id 是 51,在事务 B 的 Read View 的 min_trx_id 和 max_trx_id 之间,接下来需要判断trx_id值是否在 m_ids 范围内,判断结果在,那么说明这条记录是被未提交的事务修改的,这时事务 B 并不会读取这个版本的记录。而是沿着 undo log 链表往下找到旧版本的记录,直到找到 trx_id [小于] 事务 B 的 Read View 中的 min_trx_id 值的第一条记录,所以事务 B 能读取到的是 trx_id 为 50 的记录,也就是余额为 100 的记录。

为什么事务 A提交后,事务 B 就可以读取到 事务 A 修改的数据?

在事务 A 提交后,由于隔离级别是 [读提取] ,所以事务 B 在每次读取数据的时候,会重新创建 Read View ,此时事务 B 第三次读取数据时创建的 Read View 如下;

事务 B 在找到这条记录时,会发现这条记录的 trx_id 是 51,比事务 B 的 Read View 中的 min_trx_id 还小,说明修改这条记录的事务早就在创建 Read View 前提交过了,所以该版本的记录对事务 B 是可见的

正是因为在读提交隔离级别下,事务每次读数据时都重新创建 Read View ,那么在事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能这期间另外一个事务修改了该记录,并提交了事务。


总结

事务是在 MySQL 引擎实现的,我们常见的 InnoDB 引擎时支持事务的,事务的四大特性是原子性、一致性、隔离性、持久性

当多个事务并发执行的时候,会引发脏读,不可重复读,幻读这些问题,那为了避免这些问题,SQL提出了四种隔离级别,分别是 读未提交、读提交、可重复读、串行化、从左往右隔离级别顺序递增,隔离级别越高,意味着性能越差,InnoDB 引擎的默认隔离级别是可重复读。

要解决脏读现象,就需要将隔离级别升级到读提交以上的隔离级别,要解决不可重复读现象,就要将隔离级别升级到可重复读以上的隔离级别。

而对于幻读现象,不建议将隔离级别升级为串行化,因为这会导致数据库并发时的性能很差。MySQL InnoDB 引擎的默认隔离级别虽然是 [可重复读] ,但是它很大程度上避免幻读现象,解决的方案有两种:

  • 针对快照读(普通select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据时一样的,即使中途有其他事务修改了数据库,所以就很好的避免了幻读问题
  • 针对当前读(select  ... for update等语句),是通过next-key lock (记录锁+间隙锁)方式解决了幻读,因为当执行 select ... for update 语句的时候,会加上 next-key lock ,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好避免了幻读问题。

对于 [读提交] 和 [可重复读] 隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于 创建 Read View 的时机不同:

  • [读提交] 隔离级别是在每一个 select 都会生成一个新的 Read View ,也意味着,事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能这期间另外一个事务修改了该事务,并提交了事务。
  • [可重复读度] 隔离级别是启动事务时生成一个 Read View ,然后整个事务期间都在用这个 Read View,这样就保证了在事务期间读到的数据都是事务启动前的记录。

这两个隔离级别实现是通过 [事务的 Read View 里的字段] 和 [记录中的两个隐藏列] 的对比,来控制并发事务访问同一个记录时的行为,这就叫做 MVCC (多版本并发控制)

在可重复读的隔离级别中,普通的 select 语句就是基于 MVCC 实现的快照读,也就是不会加锁。而 select ... for update 语句就不是快照读了,而是当前读,也就是每次读都是拿到最新版本的数据,但是它会对读到的记录加上 next-key lock 锁

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

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

相关文章

Docker进阶:Docker轻量级可视化工具Portainer与容器监控3剑客CAdvisor+InfluxDB+Granfana

Docker进阶:Docker轻量级可视化工具Portainer与容器监控3剑客CAdvisorInfluxDBGranfana 一、Docker轻量级可视化工具Portainer1.1、Portainer简介1.2、安装Portainer1.2.1、安装Portainer的Docker镜像1.2.2、访问Portainer Web界面1.2.3、连接到Docker守护进程 1.3、…

SpringBoot整合Zookeeper做分布式锁

环境准备 zookeeper准备 首先你需要一个zookeeper服务器,或者是一个zookeeper集群。我已经准备好了一个zookeeper集群,如图: 当然一个单节点的zookeeper也可以搭建分布式锁。如果你还没有zookeeper,那么你可以参考我写的搭建z…

华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于 Geekbench 深度测评华为云云耀云服务器L实例

本文收录在专栏:#云计算入门与实践 - 华为云 专栏中,本系列博文还在更新中 相关华为云云耀云服务器L实例评测文章列表如下: 华为云云耀云服务器L实例评测 | 从零开始:云耀云服务器L实例的全面使用解析指南 华为云云耀云服务器L实…

某计费管理系统任意文件读取漏洞

文章目录 声明一、漏洞描述二、漏洞复现声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 一、漏洞描述 蓝海…

Apache解析漏洞复现

一、多后缀解析漏洞 1.漏洞说明 配置apache时,对于apache配置不熟练,配置命令不清楚,在配置PHP文件处理程序时,配置命令存在问题:位于漏洞环境目录的 conf/docker-php.conf里的配置命令(AddHandler applica…

uni-datetime-picker组件填坑,在mounted后再赋值calendar日历不展示或错误展示回显的日期。

当需求存在tab切换展示uni-datetime-picker&#xff0c;且每次切换需要初始化默认选中日期的时候&#xff0c;就会出现这样的bug。 就以两个不同类型的日期选择框进行切换展示为例&#xff1a; 没填坑之前的代码&#xff1a; <uni-datetime-picker v-show"activeTab…

使用BWGS进行基因型数据预测

标题&#xff1a;小麦基因组选择育种通道方法 描述&#xff1a;专门为小麦全基因组选择育种设计的包 编码方式&#xff1a;UTF-8 URL&#xff1a;GitHub - byzheng/BWGS: 2021 BreedWheat Genomic Selection pipeline BugReports &#xff1a;https://github.com/byzheng/B…

Vue2 | Vant uploader实现上传文件和图片

需求&#xff1a; 实现图片和文件的上传&#xff0c;单个图片超过1M则压缩&#xff0c;全部文件加起来不得超过10M。 效果&#xff1a; 1. html <van-form ref"form"><van-field name"uploader" label"佐证材料" required><t…

TypeScript枚举(Enums)和泛型(Generics)

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 枚举 异构枚举 枚举成员的类型 泛型 1. 函数泛型 2. 接口泛型 3. 类泛型 接下来我们将学习TypeScript 中的两…

无涯教程-JavaScript - ISREF函数

描述 如果指定的值是参考,则ISREF函数返回逻辑值TRUE。否则返回FALSE。 语法 ISREF (value) 争论 Argument描述Required/OptionalvalueA reference to a cell.Required Notes 您可以在执行任何操作之前使用此功能测试单元格的内容。 适用性 Excel 2007,Excel 2010,Exce…

机器故障预测:未来24小时的决胜时刻!!!

一、背景介绍 这个竞赛的焦点是预测机器是否会在未来24小时内故障。数据包括与机器性能相关的各种特征&#xff0c;例如温度、振动、功耗和传感器读数。目标变量是二进制的&#xff0c;表示机器是否在未来24小时内故障&#xff08;1&#xff09;或未故障&#xff08;0&#xf…

计算机竞赛 机器视觉opencv答题卡识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 答题卡识别系统 - opencv python 图像识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分…

selenium 网页自动化-在访问一个网页时弹出的浏览器窗口,我该如何处理?

前言 相信大家在使用selenium做网页自动化时&#xff0c;会遇到如下这样的一个场景&#xff1a; 在你使用get访问某一个网址时&#xff0c;会在页面中弹出如上图所示的弹出框。 首先想到是利用Alert类来处理它。 然而&#xff0c;很不幸&#xff0c;Alert类处理的结果就是没…

解决java.text.ParseException: Unparseable date: “invalid_date“

解决java.text.ParseException: Unparseable date: "invalid_date" 前言摘要引言正文1. 理解异常的根本原因2. 处理日期字符串格式问题3. 处理非法字符或无效日期信息4. 异常处理 总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f…

创造引人入胜的网页体验:掌握 CSS 动画

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 在现代网页设计中&#…

Leetcode算法入门与数组丨2. LeetCode入门

文章目录 前言LeetCode 是什么LeetCode 注册LeetCode 学习LeetCode 题库LeetCode 刷题页面 & 刷题语言选择LeetCode 题解LeetCode 刷题流程LeetCode 刷题攻略 前言 Datawhale组队学习丨9月Leetcode算法入门与数组丨打卡笔记 这篇博客是一个 入门型 的文章&#xff0c;主要…

Failed to connect to bitbucket.org port 443 错误原因, 解决办法

最近使用SourceTree来访问bitbucket.org的代码托管Git, 当Pull或者Push发现操作失败: Failed to connect to bitbucket.org port 443 错误原因: 无法链接到网站地址, 可能是DNS解析IP地址错误, 或者网站维护, 大概率是被墙或者DNS解析错误. 解决办法: 如果您的浏览器能够访问b…

iOS技术博主指南:填写苹果应用上架中的隐私政策信息

摘要&#xff1a;本文将详细介绍iOS技术博主在苹果应用上架过程中如何填写隐私政策信息。博主可以通过App Store Connect为应用程序提供隐私政策网址和用户隐私选项网址&#xff0c;并了解如何填写隐私政策文本。本文将提供步骤和注意事项&#xff0c;帮助博主顺利完成隐私政策…

数据库-理论基础

目录 1.什么是数据库&#xff1f; 2.数据库与文件系统的区别&#xff1f; 3.常见的数据库由那些&#xff1f; 4.关系型数据库(MySQL&#xff09;的特征及组成结构介绍 1.什么是数据库&#xff1f; 数据&#xff1a;描述事物的符号记录&#xff0c;可以是数字&#xff0c;文…

SSTI注入利用姿势合集

文章目录 前言SSTI模板注入原理&#xff1f;关于Python的类知识构造链的思路Jinjia2获取配置信息lipsumrequesturl_forget_flashed_messagesg对象 Jinjia2 Bypass.绕过引号绕过_绕过init过滤[ ]被过滤 羊城杯2023[决赛] SSTI2020XCTF 华为专项赛Tornado通用手法tornado.templat…