数据库的事务四大特性(ACID)、详解隔离性以及隔离级别、锁

发布时间:2026/7/5 21:25:11
数据库的事务四大特性(ACID)、详解隔离性以及隔离级别、锁 个人主页编程的一拳超人⛺️ 欢迎关注点赞 留言 收藏 于高山之巅方见大河奔涌于群峰之上更觉长风浩荡。 ——《人民日报》文章目录数据库的事务四大特性ACID以及隔离性一、事务的四大特性✨1、原子性Atomicity2、一致性Consistency3、隔离性Isolation4、持久性Durability二、详解事务的隔离性✨1、脏读2、不可重复读3、虚读(幻读)4、隔离级别1️⃣ Read uncommitted (读未提交)最低级别任何情况都无法保证。2️⃣ Read committed (读已提交)可避免脏读的发生。3️⃣ Repeatable read (可重复读)可避免脏读、不可重复读的发生。*MySQL默认隔离级别4️⃣ Serializable (串行化)可避免脏读、不可重复读、幻读的发生。三、怎样算是一个事务1、从第一次执行SQL语句开始到执行commit或者rollback结束。中间不管执行多少SQL语句都是同一个事务内。2、事务的开始与结束3、数据库如何实现事务的四、常用操作-----记住设置数据库的隔离级别一定要是在开启事务之前1、查看提交状态命令2、关闭自动提交3、查看隔离级别4、修改隔离级别5、开启事务-----只要执行一条SQL语句就是开启事务不一定非要使用start transaction;6、结束事务五、数据库事务怎么做✨1、如何进行事务1️⃣ 建立引擎支持InnoDBInnoDB支持数据库事务操作2️⃣ 设置autocommit为false3️⃣ 修改隔离级别4️⃣ 开启事务5️⃣ 执行SQL语句6️⃣ commit或者rollback回滚2、对Read Uncommitted级别进行操作1️⃣ 脏读两次数据3、对Read Committed级别进行操作2️⃣ 不可重复读-----此时避免了脏读但是还存在不可重复读的问题看此标题下第二张图4、repeatable read隔离级别3️⃣ 解决了脏读、不可重复读六、锁1、代码层次的乐观锁、删除锁2、数据库层次的悲观锁数据库的事务四大特性ACID以及隔离性一、事务的四大特性✨1、原子性Atomicity原子性是指事务包含的所有操作要么全部成功要么全部失败回滚。因此事务的操作如果成功就必须完全应用到数据库如果操作失败不能对数据库有任何影响。例子考虑银行转账操作从一个账户扣除一定金额并存入另一个账户。如果扣除成功但存入失败需要回滚保持操作的原子性。2、一致性Consistency一致性要求事务执行前后数据库的状态保持一致。事务执行过程中可能涉及多个操作这些操作的结果必须满足数据库的约束和规则。例子在购物网站上进行支付操作支付前后库存、账户余额等信息必须保持一致否则支付过程可能导致数据不一致。例如那转账来说假设用户A和用户B两者的钱加起来是5000那么不管A和B之间如何转账转几次账事务结束后两个用户的钱加起来应该还得是5000这就是事务的一致性。3、隔离性Isolation隔离性是指当多个用户并发访问数据库时比如操作同一张表时数据库为每个用户开启的事务不能被其他事务的操作干扰多个并发事务要互相隔离。即要达到一种效果对于任意两个并发的事务T1和T2在事务T1看来T2要么在T1开始之前就已经结束要么在T1结束之后开始这样每个事务都感觉不到有其他的事务在并发执行。关于事务的隔离性又提供了多种隔离级别如读已提交、读未提交、可重复读、串行化稍后会讲到。4、持久性Durability持久性是指一个事务一旦被提交了那么对数据库中的数据的改变是永久的即便是在数据库系统中遇到故障的情况下也不会丢失提交事务的操作。例如我们在使用JSDC操作数据库时在提交事务后提示用户事务操作完成当我们程序执行完成直到看到提示后就可以认定事务已经正确提交即使数据库出现了问题也必须要将我们的事务完全执行完成否则会造成我们看到提示事务处理完毕但是数据库因为故障而没有执行事务的重大错误。例子用户在博客平台上发表文章一旦用户点击发布并事务提交该文章的修改应该是永久性的即使系统在发布过程中发生了故障。二、详解事务的隔离性✨以上介绍完事务的四大特性简称ACID现在重点来说明一下事务的隔离性当多个线程都开启事务的操作数据库中的数据数据库系统要能进行隔离操作以保证各个线程获取数据的准确性在介绍数据库提供的各种隔离级别之前我们先看看如果不考虑事务的隔离性会发生哪些问题1、脏读脏读是指在一个事务处理过程里读取了另一个未提交事务中的数据。当一个事务正在多次修改某个数据而在这个事务中这多次的修改都还未提交这时一个并发的事务来访问该数据就会造成两个事务得到的数据不一致。例如用户A向用户B转账100元对应SQL命令如下updateaccountsetmoneymoney100wherename’B’;(此时A通知B)updateaccountsetmoneymoney-100wherename’A’;当只执行第一条SQL时A通知B查看账户B发现确实钱已到账此时即发生了脏读而之后无论第二条SQL是否执行只要该事务不提交则所有操作都将回滚那么当B以后再次查看账户时就会发现钱其实并没有转。2、不可重复读不可重复读是指在对于数据库中的某个数据一个事务范围内多次查询却返回了不同的数据值这是由于在查询间隔被另一个事务修改并提交了。例如事务T1在读取某一数据而事务T2立马修改了这个数据并且提交事务给数据库事务T1再次读取该数据就得到了不同的结果发送了不可重复读。不可重复读和脏读的区别是脏读是某一事务读取了另一个事务未提交的脏数据而不可重复读则是读取了前一事务提交的数据。在某些情况下不可重复读并不是问题比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题例如对于同一个数据A和B依次查询就可能不同A和B就可能打起来了……3、虚读(幻读)幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作这时事务T2又对这个表中插入了一行数据项而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据会发现还有一行没有修改其实这行是从事务T2中添加的就好像产生幻觉一样这就是发生了幻读。幻读和不可重复读都是读取了另一条已经提交的事务这点就脏读不同所不同的是不可重复读查询的都是同一个数据项而幻读针对的是一批数据整体比如数据的个数。4、隔离级别现在来看看MySQL数据库为我们提供的四种隔离级别从低到高排序1️⃣ Read uncommitted (读未提交)最低级别任何情况都无法保证。第一隔离级别怕回滚因为它能读取到别的事务未提交的数据。如果当前事务将这个数据当成真正的数据那么如果别的事务回滚那么就会数据错误导致脏读。2️⃣ Read committed (读已提交)可避免脏读的发生。第二个隔离级别怕提交因为提交会导致不可重复读。3️⃣ Repeatable read (可重复读)可避免脏读、不可重复读的发生。*MySQL默认隔离级别4️⃣ Serializable (串行化)可避免脏读、不可重复读、幻读的发生。三、怎样算是一个事务1、从第一次执行SQL语句开始到执行commit或者rollback结束。中间不管执行多少SQL语句都是同一个事务内。2、事务的开始与结束starttransaction;# 开启事务commit;或者rollback;# 事务结束3、数据库如何实现事务的服务端有日志记录功能新操作是记录到日志中的commit会将日志中的记录刷到硬盘中rollback就是将日志中的记录删除掉了四、常用操作-----记住设置数据库的隔离级别一定要是在开启事务之前1、查看提交状态命令showvariableslike%auto%;2、关闭自动提交setautocommit0;3、查看隔离级别selecttransaction_isolation;# 8.x版本数据库系统showvariablesliketransaction_isolation;# 8.x版本数据库系统SELECTtx_isolatione5.x4、修改隔离级别setsessiontransactionisolationlevel;# 8.xsetsessiontransactionisolation;# 5.x5、开启事务-----只要执行一条SQL语句就是开启事务不一定非要使用start transaction;starttransaction;6、结束事务commit;或者rollback;五、数据库事务怎么做✨以上四种隔离级别最高的是Serializable级别最低的是Read uncommitted级别当然级别越高执行效率就越低。像Serializable这样的级别就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。在MySQL数据库中支持上面四种隔离级别默认的为Repeatable read (可重复读)而在Oracle数据库中只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别其中默认的为Read committed级别。1、如何进行事务1️⃣ 建立引擎支持InnoDBInnoDB支持数据库事务操作2️⃣ 设置autocommit为falseshowvariableslike%auto%;# 展示事务提交信息setautocommit0;# 设置autocommit为falsesetautocommit1;# 设置autocommit为true3️⃣ 修改隔离级别selecttransaction_isolation;# 查看隔离级别setsessiontransactionisolationlevelreaduncommitted;# 设置隔离级别此时设置为读未提交4️⃣ 开启事务5️⃣ 执行SQL语句select*fromemployee;updateemployeesetsal100whereempno1022;6️⃣ commit或者rollback回滚commit;rollback;2、对Read Uncommitted级别进行操作1️⃣ 脏读两次数据3、对Read Committed级别进行操作2️⃣ 不可重复读-----此时避免了脏读但是还存在不可重复读的问题看此标题下第二张图因为两个事务对同一个数据进行操作违反了隔离性死锁。对不同数据操作不报错4、repeatable read隔离级别3️⃣ 解决了脏读、不可重复读记住设置数据库的隔离级别一定要是在开启事务之前如果是使用JDBC对数据库的事务设置隔离级别的话也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别至于参数level可以使用Connection对象的字段在JDBC中设置隔离级别的部分代码后记隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言一个窗口就相当于一个链接当前窗口设置的隔离级别只对当前窗口中的事务有效对于JDBC操作数据库来说一个Connection对象相当于一个链接而对于Connection对象设置的隔离级别只对该Connection对象有效与其他链接Connection对象无关。六、锁1、代码层次的乐观锁、删除锁在代码层次乐观锁是一种在数据读取时不加锁的并发控制机制。它假设多个事务在同一时间对同一数据进行操作的可能性较小因此只在更新数据时进行版本检查以防止数据被其他事务同时修改。在MySQL中可以使用版本号或时间戳等机制来实现乐观锁。例如在更新数据时可以检查该数据的版本号是否与最初读取时一致如果不一致则表示有其他事务修改了该数据此时可以选择回滚或重试等操作。2、数据库层次的悲观锁在数据库层次悲观锁是一种在数据读取时加锁的并发控制机制。它假设多个事务在同一时间对同一数据进行操作的可能性较大因此每次读取数据时都会对相应的数据进行加锁以防止其他事务同时修改该数据。在MySQL中可以使用SELECT … FOR UPDATE或SELECT … LOCK IN SHARE MODE等语句来实现悲观锁。例如使用SELECT … FOR UPDATE语句时会对选定的行进行加锁直到事务结束时才释放锁。在此期间其他事务无法对该行进行修改。