【数据库】六、事务与并发控制(封锁)

news2024/11/18 19:53:52

六、事务与并发控制

文章目录

  • 六、事务与并发控制
    • 1.事务
      • 1.1事务的ACID特性
      • 1.2MySQL事务控制语句
        • 开启事务
        • 提交事务
        • 回滚事务
    • 2.并发控制
      • 2.1并发执行可能引起的问题
        • 2.1.1丢失更新
        • 2.1.2不可重复读
        • 2.1.3读脏数据
      • 2.2并发调度的可串行性
      • 2.3并发与并行的区分
      • 2.4事务的隔离级别
    • 3.封锁
      • 3.1基本锁
      • 3.2基本锁的相容矩阵
      • 3.3锁的粒度
      • 3.4封锁协议
        • 3.4.1一级封锁协议
        • 3.4.2二级封锁协议
        • 3.4.3三级封锁协议
        • 3.4.4封锁协议总结
      • 3.5封锁带来的问题
        • 3.5.1“饿死”问题
        • 3.5.2“活锁”问题
        • 3.5.3“死锁”问题
      • 3.6两段封锁协议2PL

数据库是一个共享资源,可以供多个用户使用。

允许多个用户同时使得的数据库系统称为多用户数据库系统,例如航空订票系统、银行系统等都是多用户数据库系统。在这样的系统中,在同一时刻并发运行的事务数可达数百甚至数千个

对于多用户数据库系统而言,当多个用户并发操作时,会产生多个事务同时操作同一数据的情况。若对并发操作不加以控制,就可能发生读取和写入不正确数据的情况,从而破坏了数据库的一致性,所以数据库管理系统必须提供并发控制机制。

1.事务

所谓的事务是指由用户定义的一系列数据库更新操作,这些操作,要么都执行,要么都不执行,是一个不可分割的逻辑工作单元。这里的更新操作主要指对数据库内容产生修改作用的操作,比如:insert、delete、update等操作。

  • 如果事务成功执行,那么该事务中所有的更新操作都会成功执行,并将执行结果提交到数据库文件中,成为数据库永久的组成部分。
  • 如果事务中某个更新操作执行失败,那么事务中的所有更新操作均被撤消。简言之:事务中的更新操作要么都执行,要么都不执行。

1.1事务的ACID特性

为了保证事务对数据操作的完整性,对事务需要加以要求和限制,只有满足这些要求或限制才能使数据库在任何情况下都是正确有效的,这是DBMS的责任。

DBMS为了保证在并发访问时对数据库的保护,要求事务具有4个特性,即,简称ACID特性

  • 原子性(Atomicity)

    原子性体现事务所有操作是否被全部完成。事务处理的操作要么全都完成,要么全都不做,如果有操作失败,整个事务将要回滚,从而保证事务所有操作成功必将完成所有的数据库修改任务,如果有操作失败数据库将恢复到事务开始之前的状态。

  • 一致性(Consistency)

    一致性是指事务必须在执行前后都要处于一致性状态。事务操作全部正确执行,数据库的变化将生效,从而处于有效状态;如果事务处理失败,系统将会回滚,从而恢复到执行前的状态,由于执行前系统处于一致性状态,所以回滚后系统仍然处于一致性状态。

  • 隔离性(Isolation)

    隔离性是面对多用户并发对数据库访问时,要保证所有并发事务认为只有自己在使用系统,而不为其他事务的操作所干扰

  • 持久性(Durability)

    持久性是指一旦一个事务被完成,那么系统中的数据的改变将会是永久的,即使系统遭遇了故障的情况下,也不会丢失提交事务的操作。

1.2MySQL事务控制语句

开启事务

事务处理首先要开启事务,使用的语句如下所示:

START TRANSACTION;
提交事务

开启事务之后,就开始执行事务内的SQL语句,当SQL语句执行完毕后,必须使用语句提交事务,使用的语句如下:

COMMIT;
回滚事务

开启事务之后,事务中的SQL语句只有在提交事务之后才能运行生效。在提交事务之前,还可以使用语句取消当前事务,叫做回滚事务,具体如下:

ROLLBACK;

例子:

-- 【例11-1】假设银行存在两个借记卡账户“李三”和“王五”,要求这两个借记卡账户不能用于透支,即两个账户的余额(balance)不能小于0。创建存储过程tran_proc,实现两个账户的转账业务。
#建立account表
CREATE TABLE account(
  Account_no INT PRIMARY KEY,
  Account_name VARCHAR(10) NOT NULL,
  Balance INT UNSIGNED );
#向account表插入记录
  INSERT INTO account VALUES(1, '李三',1000);
  INSERT INTO account VALUES(2, '王五',1000);
-- 【例11-1】假设银行存在两个借记卡账户“李三”和“王五”,要求这两个借记卡账户不能用于透支,即两个账户的余额(balance)不能小于0。创建存储过程tran_proc,实现两个账户的转账业务。
#建立account表
CREATE TABLE account(
  Account_no INT PRIMARY KEY,
  Account_name VARCHAR(10) NOT NULL,
  Balance INT UNSIGNED );
#向account表插入记录
  INSERT INTO account VALUES(1, '李三',1000);
  INSERT INTO account VALUES(2, '王五',1000);

结果

-- 第一次转账业务可以正确实现,结果如图11.1所示。
CALL tran_proc(1,2,800);
SELECT * FROM account;

-- 第二次转账业务由于转账金额超过余额,因此未能正确实现,执行结果如图11.2所示。
CALL tran_proc(1,2,500);
SELECT * FROM account;

2.并发控制

事务的并发执行:

DBMS同时执行多个事务对同一数据的操作,为此DBMS要对各事务中的操作顺序进行安排,以达到同时运行多个事务的目的。这里的并发是指在单处理器上利用分时方法实现多个事务同时操作

2.1并发执行可能引起的问题

事务中的操作归根结底就是读或写。

两个事务之间的相互干扰就是其操作彼此冲突。因此,事务间的相互干扰问题可归纳为写-写读-写写-读3种冲突(读-读不冲突),分别称为“丢失更新”、“不可重复读”、“读脏数据”问题。

2.1.1丢失更新

丢失更新又称为覆盖未提交的数据。也就是说,一个事务更新的数据尚未提交,另一事务又将该未提交的更新数据再次更新,使得前一个事务更新的数据丢失

原因:由于两个(或多个)事务对同一数据并发地写入引起,称为写-写冲突。

结果:与串行地执行两个(或多个)事务的结果不一致。

【例11-3】在表11-1中,数据库中A的初值是100,事务T1对A的值减30,事务T2对A的值增加一倍。
如果执行顺序是先T1后T2,那么结果A的值是140;如果是先T2后T1,那么A的值是170。这两种情况都应该是正确的。但是按表11-1中的并发执行,结果A的值是200,这个值肯定是错误的,因为在时间t0丢失了事务T1对数据库的更新操作。所以这个并发操作是不正确的。

时间事务T1A的值事务T2
t0R(A)100
t1100R(A)
t2A:=A-30
t3A;=A*2
t4W(A)70
t5200W(A)
2.1.2不可重复读

不可重复读也称为读值不可复现。由于另一事务对同一数据的写入,一个事务对该数据两次读到的值不一样

原因:该问题因读-写冲突引起。

结果:第二次读的值与前次读的值不同。

【例11-4】表11-2表示T1需要两次读取同一数据项A,但是在两次读取操作的间隔中,另一事务T2改变了A的值。因此,T1在两次读同一数据项A时却读出不同的值。

时间事务T1A的值事务T2
t0R(A)100
t1100R(A)
t2A:=A*2
t3200W(A)
t4COMMIT
t5R(A)200
2.1.3读脏数据

读脏数据也称为读未提交的数据。也就是说一个事务更新的数据尚未提交,被另一事务读到,如前一事务因故要回滚,则后一事务读到的数据已经是没有意义的数据了,即为脏数据

原因:由于后一事务读了前一事务写了但尚未提交的数据引起,称为写-读冲突。

结果:读到有可能要回滚的更新数据。但如果前一事务不回滚,那么后一事务读到的数据仍然是有意义的。

【例11-5】表11-3中事务T1把A的值修改为70,但尚未提交(即未做COMMIT操作),事务T2紧跟着读未提交的A值70。随后,事务T1做了ROLLBACK操作,把A的值恢复为100,而事务T2仍在使用被撤消了的A值70。

时间事务T1A的值事务T2
t0R(A)100
t1A:=A-30
t2W(A)70
t370R(A)
t4ROLLBACK100

产生上述3类数据不一致性的主要原因是并发操作破坏了事务的隔离性

并发控制就是要求DBMS提供并发控制功能,以正确的方式执行并发事务,避免并发事务之间相互干扰造成数据的不一致性,保证数据库的完整性和一致性。

2.2并发调度的可串行性

  1. 多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同,称这种调度策略为可串行化的调度。
  2. 可串行性是并发事务正确性的准则。按这个准则规定,一个给定的并发调度,当且仅当它是串行化的,才认为是正确调度。

2.3并发与并行的区分

  • 并发(Concurrent)**:**当有多个线程在操作时,如果系统只有一个CPU,则它不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。
  • 并行(Parallel):当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行。

**区别:**并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。

2.4事务的隔离级别

隔离性是事务最重要的基本特性之一,是解决事务并发执行时可能发生的相互干扰问题的基本技术。

隔离级别定义了一个事务与其他事务的隔离程度

为了更好地理解隔离级别,再来看并发事务对同一数据库进行访问可能发生的情况。在并发事务中,总的来说会发生以下3种异常情况。

在并发事务中,总的来说会发生以下3种情况:

(1)丢失更新
丢失更新就是一个事务更新的数据尚未提交,另一事务又将该未提交的更新数据再次更新,使得前一个事务更新的数据丢失。

(2)不可重复读
不可重复读是指当一个事务读取数据库中的数据后,另一个事务更新了数据,当第一个事务再次读取该数据时,发现数据已经发生改变,导致一个事务前后两次读取的数据值不相同。

(3)读脏数据
读脏数据就是当一个事务修改数据时,另一个事务读取了修改的数据,并且第一个事务由于某种原因取消了对数据的修改,使数据库回到原来的状态,这时第二个事务中读取的数据与数据库中的数据已经不相符。

隔离级别分为以下4级:

(1)未提交读(READ UNCOMMITED):
在此隔离级别下,用户可以对数据执行未提交读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。它是4个级别中限制最小的级别。

(2)提交读(READ COMMITED):
此隔离级别不允许用户读一些未提交的数据,因此不会出现读脏数据的情况,但数据可以在事务结束前被修改,从而产生不可重复读。

(3)可重复读(REPEATABLE READ):
此隔离级别保证在一个事务中重复读到的数据会保持同样的值,而不会出现读脏数据、不可重复读的问题。但允许其他用户将新的幻影行插入数据集,且幻影行包括在当前事务的后续读取中。

(4)可串行读(SERIALIZABLE):
此隔离级别是4个隔离级别中限制最大的级别,不允许其他用户在事务完成之前更新数据集或将行插入到数据集内

4种隔离级别允许的不同类型的行为:

隔离级别丢失更新读脏数据不可重复度
未提交读
(READ UNCOMMITED)
提交读
(READ COMMITED)
可重复读
(REPEATABLE READ)
可串行读
(SERIALIZABLE)

3.封锁

封锁是实现并发控制的一个非常重要的技术。所谓封锁,就是事务T在对某个数据对象(例如表、记录等)操作之前先向系统发出请求,对其加锁

一个锁实质上就是允许(或阻止)一个事务对一个数据对象的存取特权。一个事务对一个对象加锁的结果是将别的事务封锁在该对象之外,特别是防止了其他事务对该对象的更改,而加锁的事务则可执行它所希望的处理,并维持该对象的正确状态。一个锁总是与某一事务的一个操作相联系的。

3.1基本锁

锁可以有多种不同的类型,最基本的有两种,即排他锁(Exclusive Locks)和共享锁(Share Locks)。

  1. 排他锁(X锁)

排他锁又称为写锁。若一个事务T1在数据对象R上获得了排他锁,则T1既可对R进行读操作,也可进行写操作。其他任何事务不能对R加任何锁,因而不能进行任何操作,直到T1释放了它对R加的锁。所以排他锁就是独占锁

  1. 共享锁(S锁)

共享锁又称为读锁。若一个事务T1在数据对象R上获得了共享锁,则它能对R进行读操作,但不能写R。其他事务可以也只能同时对R加共享锁。

显然,排他锁比共享锁更“强”,因为共享锁只禁止其他事务的写操作,而排他锁既禁止其他事务的写又禁止读。

常用XLOCK表示对A上加X锁,SLOCK表示对A加S锁,UNLOCK A表示释放A上的封锁。

3.2基本锁的相容矩阵

根据X锁、S锁的定义,可以得出基本锁的相容矩阵,如表11-5所示。表中表明,当一个数据对象R已被事务持有一个锁,而另一事务又想在R上加一个锁时,只有两种锁同为共享型锁才有可能。如果要请求对R加一个排他锁,只有在R上无任何事务持有锁时才可以。

请求锁请求锁请求锁
持有锁SX
SYNY
XNNY
YYY

3.3锁的粒度

封锁对象的大小称为封锁的粒度(Lock Granularity)。

根据对数据的不同处理,封锁的对象可以是字段、记录、表、数据库等逻辑单元,也可以是页(数据页或索引页)、块等物理单元。

封锁粒度与系统的并发度和并发控制的开销密切相关。

封锁粒度越小,系统中能够被封锁的对象就越多,但封锁机构复杂,系统开销也就越大;相反,封锁粒度越大,系统中能够被封锁的对象就越少,并发度越小,封锁机构简单,相应系统开销也就越小。

因此,在实际应用中选择封锁粒度应同时考虑封锁机构和并发度两个因素,对系统开销并发度进行权衡,以求得最优的效果。一般来说,需要处理大量元组的用户事务可以以关系为封锁单元;而对于一个处理少量元组的用户事务,可以以元组为封锁单元,以提高并发度。

3.4封锁协议

在运用封锁机制时还需要约定一些规则,例如何时开始封锁、封锁多长时间、何时释放等,这些封锁规则称为封锁协议(lock protocol)。

前面讲过的并发操作所带来的丢失更新、读脏数据和不可重复读等数据不一致性问题,可以通过三级封锁协议在不同程度上给予解决。

3.4.1一级封锁协议

一级封锁协议的内容:事务T在修改数据对象之前必须对其加X锁,直到事务结束

一级封锁协议规定事务在更新数据对象时必须获得X锁,使得两个同时要求更新R的并行事务之一必须在一个事务更新操作执行完成之后才能获得X锁,这样就避免了两个事务读到同一个R值而先后更新所发生的数据丢失更新问题。

但一级封锁协议只有当修改数据时才进行加锁,如果只是读取数据,并不加锁,所以它不能防止读脏数据和不可重复读的情况。

解决数据丢失问题:

时间事务T1A的值事务T2
t0XLOCK A
t1R(A)100
t2XLOCK A
t3A:=A-30等待
t4W(A)70等待
t5COMMIT等待
t6UNLOCK X等待
t7XLOCK A
t870R(A)
t9A:=A*2
t10140W(A)
t11COMMIT
t12UNLOCK X
3.4.2二级封锁协议

二级封锁协议的内容:在一级封锁协议的基础上加上“事务T在读取数据对象R之前必须先对其加S锁,读完后释放S锁”

二级封锁协议不但可以解决数据丢失更新问题,还可以进一步防止读脏数据。但二级封锁协议在读取数据之后立即释放S锁,所以它仍然不能解决不可重复读的问题。

解决读脏数据问题:

时间事务T1A的值事务T2
t0XLOCK A
t1R(A)100
t2A:=A-30
t3W(A)70
t4SLOCK A
t5ROLLBACK100等待
t6UNLOCK X等待
t7SLOCK A
t8100R(A)
t9COMMIT
t10UNLOCK S
3.4.3三级封锁协议

三级封锁协议的内容:在一级封锁协议的基础上加上“事务T在读取数据R之前必须先对其加S锁,读完后并不释放S锁,直到事务T结束才释放”

所以三级封锁协议除了可以防止丢失更新和读脏数据外,还可以进一步防止不可重复读,彻底解决了并发操作带来的三种不一致性问题。

解决不可重复读问题:

时间事务T1A的值事务T2
t0SLOCK A
t1R(A)100
t2XLOCK A
t3R(A)100等待
t4COMMIT等待
t5UNLOCK S等待
t6XLOCK A
t7100R(A)
t8A:=A*2
t9200W(A)
t10COMMIT
t11UNLOCK X
3.4.4封锁协议总结

请添加图片描述

3.5封锁带来的问题

利用封锁技术可以避免并发操作引起的各种错误,但有可能产生新的问题,即活锁饿死死锁

3.5.1“饿死”问题

有可能存在一个事务序列,其中的每个事务都申请对某数据项加S锁,且每个事务在授权加锁后一小段时间内释放封锁,此时若另一事务T2要在该数据项上加X锁,则将永远轮不上封锁的机会。这种现象称为“饿死”(Starvation)。

可以用下列授权方式来避免事务被“饿死”。

当事务T中请求对数据R加S锁时,授权加锁的条件如下:

(1)不存在数据R上持有X锁的其他事务。
(2)不存在等待对数据R加锁且先于T申请加锁的事务。

3.5.2“活锁”问题

系统可能使某个事务永远处于等待状态,得不到封锁的机会,这种现象为“活锁”(live lock)。

例如,事务T1在对数据R封锁后,事务T2又请求封锁R,于是T2等待;T3也请求封锁R,当T1释放R上的封锁后,系统首先批准了T3的请求,T2继续等待;然后又有T4请求封锁R,T3释放了R上的封锁后,系统又批准了T4的请示;依此类推,T2可能永远处于等待状态,从而发生“活锁”。

解决“活锁”问题的一种简单方法是采用“先来先服务”的策略。

3.5.3“死锁”问题

系统中两个或两个以上的事务都处于等待状态,并且每个事务都在等待其中另一个事务解除封锁,才能继续执行下去,结果造成任何一个事务都无法继续执行,这种现象称系统进入“死锁”(dead lock)状态。

例如,事务T1等待事务T2释放它对数据对象持有的锁,事务T2等待事务T3释放它的锁,依此类推,最后事务Tn又等待T1释放它持有的某个锁,从而形成了一个锁的等待圈,产生“死锁”。


  1. “死锁”的预防

预防死锁有两种方法,即一次加锁法和顺序加锁法。

(1)一次加锁法
一次加锁法是每个事务必须将所有要使用的数据对象全部依次加锁,并要求加锁成功,只要一个加锁不成功,则表示本次加锁失败,应该立即释放所有已加锁成功的数据对象,然后重新开始从头加锁。

(2)顺序加锁法
顺序加锁法是预先对所有可加锁的数据对象强加一个封锁的顺序,同时要求所有事务都只能按此顺序封锁数据对象。

  1. “死锁”的检测与解除

预防死锁的代价太高,还可能发生许多不必要的回退操作。因此,现在大多数DBMS采用的方法是允许死锁发生,然后设法发现它、解除它。

死锁的检测:利用事务等待图测试系统中是否存在死锁。

死锁的解除:死锁测试程序

3.6两段封锁协议2PL

DBMS对并发事务不同的调度(即事务的执行次序)可能会产生不同的结果,那么什么样的调度是正确的呢?

显然,串行调度是正确的,执行结果等价于串行调度的调度也是正确的,这样的调度称为可串行化调度

前面说明了封锁是一种最常用的并发控制技术,可串行性是并发调度的一种正确性准则

接下来的问题是怎么封锁其调度才是可串行化的?最简单而有效的方法是采用两段封锁协议(Two-Phase Locking protocol,2PL协议)。

两段封锁协议规定所有的事务应遵守下面两条规则:

(1)在对任何一个数据进行读/写操作之前,首先要申请并获得对该数据的封锁。
(2)在释放一个封锁后,事务不再申请和获得任何其他封锁。

两段锁的含义是,事务分为两个阶段。

第一阶段是获得封锁,也称为“扩展”阶段。在这个阶段,事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁;

第二阶段是释放封锁,也称为“收缩”阶段,在这个阶段,事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁。

遗憾的是,两段封锁协议仍有可能导致死锁的发生,而且可能会增多,这是因为每个事务都不能及时解除被它封锁的数据。

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

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

相关文章

Hadoop 2.0 大家族(四)

目录 七、Flume(一)Flume简介(二)Flume入门 八、Mahout(一)Mahout简介(二)Mahout入门 七、Flume Flume是一个分布式高性能、高可靠的数据传输工具,它可用简单的方式将不同…

【unity小技巧】unity事件系统创建通用的对象交互的功能

文章目录 前言实现1. **InteractEvent 类**:2. **Interact 类**:3. **Player 类**:4. **Chest 类**: 工作流程说明:开单个箱子按钮触发打开很多箱子拾取物品(传参)参考完结 前言 游戏开发过程中…

系统编程:线程相关

线程 相关函数及过程: 创建线程号; pthread_t tid; 创建线程:pthread_create(&tid, NULL, task, argv[1]); 定义线程执行函数:void *task(void *arg){ 线程退出:pthread_exit(ret);//线程结束后退出 } 等待所有线程结束:pthread_join(tid, (void **)&ret); 编译时增加…

系统思考—结构影响行为

思‮问考‬题时,从“结构”的‮度角‬出发,能‮示揭‬许多不‮人为‬知的‮层深‬次真相。我‮常们‬认为“努‮必力‬有回报”,从‮误而‬信‮过通‬坚‮就持‬能‮抗抵‬诱惑。然而,如‮深果‬入理解“结‮影构‬响行为”&#…

力扣-两数之和

文章目录 题目题解方法1-暴力方法2-哈希 题目 原题链接:两数之和 题解 方法1-暴力 我最先想到的方法就是暴力,两层for循环,也能通过。(拿到算法题在没有思路的时候暴力就是思路,哈哈哈) public class T…

【源码】含70演示高转化率Magento2外贸时装女装跨境电商模板V1.2.2

MagMog是下一代最高转化率和可扩展的跨境电商Magento2主题,让您几乎可以立即上手。这是一个终极解决方案:主题附带一系列电子商务功能,可以启用您商店的隐藏功能,并且您无需支付任何额外费用。 100% 免费。 MagMog从定制设计到内…

华为HDC开发者大会鸿蒙进展超预期

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 在数字化浪潮的推动下,华为鸿蒙系统(HarmonyOS)以其革命性的创新,引领着全球科技的新趋势。2024…

【科技前沿】电子设计新贵SmartEDA:为何它引领行业风潮?

在当今这个电子科技日新月异的时代,电子设计工具如同设计师的魔法棒,不断推动着产品创新的速度。而近期,一款名为SmartEDA的电子国产设计仿真软件异军突起,成为了行业内的新宠。那么,SmartEDA究竟有何过人之处&#xf…

智能客服到个人助理,国内AI大模型如何改变我们的生活?

引言 随着人工智能(AI)技术的高速发展,AI大模型越来越多地出现在我们的日常生活和工作中。国内的AI大模型在过去几年里取得了显著的进展,不少独创的技术点和实际应用令人瞩目。 那么,国内的AI大模型有哪些独创的技术…

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其…

根据正则表达式查找字符串中第一次出现的一个或多个连续数字并返回起止位置re.rearch

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 根据正则表达式 查找字符串中 第一次出现的 一个或多个连续数字 并返回起止位置 re.rearch [太阳]选择题 根据给定的Python代码,哪个选项是正确的? import re patte…

csp 2023 入门级题解(上)

csp 2023 入门级题解 上 第一题第二题第三题结构体联合体 第四题第五题第六题第7题第八题 第一题 unsigned是指无符号,用于int类型,是指自然数. const是定义常量,定义后的值不可修改. static是将系统栈中的变量放入内存,可以让其他程序调用 答案是c 第二题 答案d 第三题 s…

PowerToys常用工具安装使用

1、上个链接: Release Release v0.81.1 microsoft/PowerToys GitHub 2、看一下界面 3、我们看一下颜色选择器,经常会用到 winshiftc可以启用。 屏幕也可以直接取色。还是比较方便的。 直接复制,就可以了。

Spring Boot集成Redisson

文章目录 Spring Boot集成Redisson1. Redisson概述2. Redission作用3. 集成Redission前提:步骤 1: 添加依赖步骤 2: 配置Redisson 4. 结论 Spring Boot集成Redisson 1. Redisson概述 Redisson是一个在Redis基础上实现的Java驻内存数据网格(In-Memory D…

LLM之表格理解任务-文本模态

这一章我们聊聊大模型表格理解任务,在大模型时代主要出现在包含表格的RAG任务,以及表格操作数据抽取文本对比等任务中。这一章先聊单一的文本模态,既你已经通过OCR或者多模态等方式从PDF或者图片中获取了表格的文本数据。和前文相同&#xff…

开放式耳机哪个品牌最好?五大必看开放式耳机推荐2024

想要购买开放式耳机,但面对众多品牌和型号,你是否感到无从下手?别担心,作为耳机发烧友和测评专家,我为大家带来了几款热门开放式耳机的横向对比。从音质、设计、功能等方面进行详细对比,让你一目了然地了解…

受用一生的三种顶级思维

斯坦福大学心理学教授卡罗尔德韦克在《终身成长》中提到: 决定人与人之间差异的,不是天赋,不是勤奋程度,而是思维模式。 在许多情况下,拥有恰当的思维方式,甚至比单纯的努力更加关键。 普通的人改变结果…

贺尔碧格流量阀比例放大器PSR2BE10P25、PSR2BE10P30、PSR2BE10P25

PSR2BE04N06、PSR2BE04P10、PSR2BE04P06、PSR2BE04N10、PSR2BE10N12、PSR2BE10P25、PSR2BE10P30、PSR2BE10P25、PSR3BE10N25、PSR3BE10P30、PSR3BE10P12贺尔碧格HOERBIGER液压比例流量阀由比例电磁铁和流量阀组合而成,利用输入的电信号来改变节流阀的开度&#xff0…

适用于 Android 的 几种短信恢复应用程序

Android 设备上的短信丢失可能由于多种原因而丢失,例如意外删除、恢复出厂设置、系统崩溃或病毒攻击。是否有应用程序可以恢复 Android 上已删除的短信?幸运的是,有几款短信恢复应用程序可以扫描您的 Android 手机并从内存或 SIM 卡中检索已删…

手机照片怎么恢复?3个方法,从灾难中崛起

已经成为了我们随身携带的必备品。而在这些小巧玲珑的设备中,存储着我们大量的个人回忆和重要资料。其中,手机拍摄的照片更是承载着我们的欢笑、泪水、成长与经历,但它们会因为意外从此消失。 面对这样的困境,我们是否只能无奈接…