SQL——事务

这篇具有很好参考价值的文章主要介绍了SQL——事务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎈 什么是事务

💧 概念

  事务是用于保证数据的一致性,它由一组相关的DML(增、删、改)语句,该组的DML语句要么全部成功,要么全部失败。使用事务可以确保数据库的一致性和完整性,避免数据出现异常或不一致的情况。

💧 特性

  在 SQL 中,事务是指一组数据库操作,它们被视为单个逻辑单元并必须全部成功或全部失败。如果其中任何一个操作失败,则整个事务都会被回滚到之前的状态,保证数据的一致性和完整性。每个事务都拥有以下四个特性(简称ACID):

  1. 原子性(Atomicity):事务应该被视为一个原子操作,即要么全部成功,要么全部失败。如果任何单个操作失败,整个事务将回滚并且不会对数据库产生任何影响。

  2. 一致性(Consistency):事务执行后,数据库应该保持一个一致性状态。一致性状态是由事务操作所指定的约束条件定义的,也就是说,事务所做的任何更改都必须遵守其定义的约束条件。

  3. 隔离性(Isolation):事务应该与其他并发执行的事务隔离开来,以确保事务间不会相互干扰。通过各种技术,如锁定机制和多版本并发控制(MVCC),可以实现高度的隔离性。

  4. 持久性(Durability):一旦事务提交,其更改就应该永久保存在数据库中,即使系统发生故障或电源被关闭也是如此。这通常通过将更改写入磁盘或其他非易失性存储介质来实现。

  总之,事务是在 SQL 中用于处理一组数据库操作的机制,其中的 ACID 特性确保了事务的原子性、一致性、隔离性和持久性,从而确保了数据的完整性和可靠性。
  在SQL中,可以使用BEGIN TRANSACTION 、COMMIT和ROLLBACK等关键字来控制事务。BEGIN TRANSACTION开始一个新的事务,COMMIT语句提交事务,ROLLBACK语句则是回滚事务。

💧 基本操作

🔥 事务的几个重要操作

  1. start transaction – 开始一个事务
  2. savapoint 保存点名 – 设置保存点
  3. rollback to 保存点名 – 回退事务到保存点
  4. rollback – 回退全部事务
  5. commit – 提交事务,所有操作全部生效,不能回退。

🔥 回退事务

  在回退事务前,要先了解下保存点(savepoint)。保存点是事务中的点,用于取消部分事务,当结束事务(commit)时会自动删除该事务所定义的所有保存点。
  当执行回退事务时,通过指定保存点可以回退到指定的点。

🔥 提交事务

  使用commit语句可以提交事务。当执行了commit语句后,会确认事务的变化、结束事务、删除保存点、释放锁、数据生效。当使用commit语句结束事务后,其他会话将可以查看事务变化后的数据。

🔥 事务注意事项

  1. 如果不开始事务,默认情况下,DML操作时自动提交的,不能回滚。

    INSERT INTO goods VALUES (1,'java开发',29.9,'编程类','图书馆');
    SELECT * FROM `goods` ;
    

    SQL——事务

  2. 如果开始一个事务,没有创建保存点,可一致性rollback也就是默认回退到事务开始时的状态。

    -- 开启事务
    START TRANSACTION;
    -- 插入数据
    INSERT INTO goods VALUES (2,'C#开发',30.9,'编程类','图书馆');
    SELECT * FROM `goods` 
    

    SQL——事务

    -- 回滚 直接回退到事务开始时的状态。
    ROLLBACK;
    SELECT * FROM `goods` 
    

    SQL——事务

  3. 可以在事务中(未提交时),创建多个保存点。例:savepoint aaa;执行dml, savepoint bbb;

    START TRANSACTION;
    SAVEPOINT point_a;
    INSERT INTO goods VALUES (3,'C++开发',30.9,'编程类','图书馆');
    SELECT * FROM `goods` 
    

    SQL——事务

    ROLLBACK TO point_a;
    

    SQL——事务

  4. 可以在事务没有提交前,选择回退到某个保存点。

  5. mysql的事务机制需要innodb的存储引擎还可以使用,myisam不好使。

  6. 开始一个事务 start transaction,set autocommit=off;

💧 事务的隔离级别

  事务的隔离级别(Isolation Level)是指多个事务同时操作相同的数据时,系统要如何处理它们之间的相互影响和冲突的程度。目前,SQL标准定义了4种基本事务隔离级别。分别是:

  1. Read Uncommitted(未提交读):事务中的修改,即使没有提交,对其他事务也是可见的。
  2. Read Committed(提交读):一个事务只能看见已经提交的事务所做的修改。
  3. Repeatable Read(重复读):在同一事务中,查询同一个记录会返回相同的结果,即使在这个事务种其他地方已经修改过这个记录。
  4. Serialize(串行化):所有事务依次逐个执行,这样每个事务都感觉不到其他事务的存在。

  在不同的隔离级别具有不同的并发控制机制,隔离级别越高,并发性能越差,但是数据一致性性越高。而较低的隔离级别可以提高并发性能,但是可能导致脏读、不可重复读和幻读等问题。

  • 脏读(dirty read):当一个事务读取另一个事务尚未提交的改变(insert、update、delete)时,产生脏读。
  • 不可重复读(nonrepeatable read):同一个查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生不可重复读。
  • 幻读(phantom read):同一个查询在同一事物中多次进行,由于其他提交事务所做的插入或删除操作,每次返回不同的结果集,此时返回幻读。

MYSQL隔离级别定义了事务于事务之间的隔离程度。

mysql隔离级别 脏读 不可重复读 幻读 加锁读
Read Uncommitted(未提交读) 不加锁
Read Committed(提交读) 不加锁
Repeatable Read(重复读) 不加锁
Serializable(串行化) 加锁

说明:✔表示可能出现。❌表示不会出现。

🔥 事务隔离级别演示

🌀 未提交读(Read Uncommitted)隔离级别演示
  1. 开启两个mysql的控制台。
    mysql -u root -p
    
  2. 查看当前mysql的隔离级别。
    select @@transaction_isolation;
    
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | REPEATABLE-READ         |
    +-------------------------+
    1 row in set (0.00 sec)
    
  3. 把其中一个控制台的控制台的隔离级别设置为 Read Uncommitted(未提交读)
    -- 修改隔离级别。
    set session transaction isolation level read uncommitted;
    
    SQL——事务
  4. 表测试
    Repeatable Read级别窗口:
    -- 在级别为Repeatable Read的窗口创建表
    create table `account` (
    	id int,
    	'name' varchar(32),
    	money int
    );
    -- 创建事务。
    start transaction;
    -- 等`Read Uncommitted`级别窗口创建事务后,然后插入数据
    insert into account value(1,'ning',8000);
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    
    Read Uncommitted级别窗口:
    -- 创建事务。
    start transaction;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    
      结果发现,即便开启了事务,在Read Uncommitted级别窗口依旧能查看到Repeatable Read的窗口的数据,这种结果就是脏读
    Repeatable Read级别窗口:
    -- 再修改数据
    update account set money=10000 where id=1;
    -- 提交事务
    commit;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning | 10000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    
    Read Uncommitted级别窗口:
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning | 10000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    
      结果来看,在Repeatable Read的窗口执行插入修改操作并提交后,Read Uncommitted级别窗口依旧能看到变化,也就是影响了Read Uncommitted级别窗口对于这个表的读的操作,这种结果就是幻读和不可重复读。
      而正常的事务,我们应该查到的是事务开始前的数据(不会发生改变)不受到除本事务外的操作的影响,现在却能看到数据在发生改变,这就是因为事务的隔离等级较低,数据的一致性也较低。
🌀 提交读(Read Committed)隔离级别演示
  1. 开启两个mysql的控制台。
    mysql -u root -p
    
  2. 查看当前mysql的隔离级别。
    select @@transaction_isolation;
    
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | REPEATABLE-READ         |
    +-------------------------+
    1 row in set (0.00 sec)
    
  3. 把其中一个控制台的控制台的隔离级别设置为 Read Uncommitted(未提交读)
    -- 修改隔离级别。
    set session transaction isolation level read committed;
    
    SQL——事务
  4. 表测试
    Repeatable Read级别窗口:
    -- 创建事务。
    start transaction;
    -- 等`Read Committed`级别窗口创建事务后,在account表插入数据
    insert into account value (3,'qing',5000);
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    2 | Ming | 10000 |
    |    3 | qing |  5000 |
    +------+------+-------+
    3 rows in set (0.00 sec)
    
    Read Committed级别窗口:
    -- 创建事务。
    start transaction;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    2 | Ming | 10000 |
    +------+------+-------+
    2 rows in set (0.00 sec)
    
      结果发现,在Repeatable Read级别窗口插入数据,但未提交(commit)时,Read Committed级别窗口并不能看到数据变化,也就是没有发生脏读
    Repeatable Read级别窗口:
    -- 再修改数据
    update account set money=15000 where id=2;
    -- 提交事务
    commit;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    2 | Ming | 15000 |
    |    3 | qing |  5000 |
    +------+------+-------+
    3 rows in set (0.00 sec)
    
    Read Committed级别窗口:
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    2 | Ming | 15000 |
    |    3 | qing |  5000 |
    +------+------+-------+
    3 rows in set (0.00 sec)
    
      结果来看,在Repeatable Read的窗口插入修改操作并提交后,Read Uncommitted级别窗口能看到数据变化,也就是影响了Read Uncommitted级别窗口对于这个表的读的操作,这种结果就是幻读不可重复读
🌀 重复读(Repeatable Read)隔离级别演示
  1. 开启两个mysql的控制台。

    mysql -u root -p
    
  2. 查看当前mysql的隔离级别。

    select @@transaction_isolation;
    
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | REPEATABLE-READ         |
    +-------------------------+
    1 row in set (0.00 sec)
    
  3. 确认两个窗口都是 重复读(Repeatable Read)隔离级别,不是则修改

    -- 修改隔离级别。
    set session transaction isolation level repeatable read;
    

    SQL——事务

  4. 表测试
    Repeatable Read级别窗口A

    -- 创建事务。
    start transaction;
    -- 等B窗口创建事务后,在account表插入数据
    insert into account value (4,'tian',10000);
    -- 修改数据
    update account set money=8000 where id=1;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    4 | tian | 10000 |
    +------+------+-------+
    2 rows in set (0.00 sec)
    

    Repeatable Read级别窗口B

    -- 创建事务。
    start transaction;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning | 10000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    

      结果发现,在窗口A插入数据,但未提交(commit)时,窗口B并不能看到数据变化,也就是没有发生脏读
    Repeatable Read级别窗口A

    -- 提交事务
    commit;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    4 | tian | 10000 |
    +------+------+-------+
    2 rows in set (0.00 sec)
    

    Read Committed级别窗口B

    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning | 10000 |
    +------+------+-------+
    1 row in set (0.00 sec)
    

      结果来看,在窗口A执行插入修改操作并提交后,窗口B能依旧看不到数据变化,这种结果就是没有出现幻读不可重复读文章来源地址https://www.toymoban.com/news/detail-477030.html

🌀 串行化(Serializable)隔离级别演示
  1. 开启两个mysql的控制台。
    mysql -u root -p
    
  2. 查看当前mysql的隔离级别。
    select @@transaction_isolation;
    
    +-------------------------+
    | @@transaction_isolation |
    +-------------------------+
    | REPEATABLE-READ         |
    +-------------------------+
    1 row in set (0.00 sec)
    
  3. 修改一个窗口隔离级别为串行化(Serializable)
    -- 修改隔离级别。
    set session transaction isolation level Serializable;
    
  4. 表测试
    Repeatable Read级别窗口A
    -- 创建事务。
    start transaction;
    -- 等B窗口创建事务后,在account表插入数据
    insert into account value (5,'369',12000);
    -- 修改数据
    update account set money=9000 where id=4;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    4 | tian |  9000 |
    |    5 | 369  | 12000 |
    +------+------+-------+
    
    Serializable级别窗口B
    -- 创建事务。
    start transaction;
    -- 查询数据
    select * from account;
    -- 结果会发现程序卡在这里。
    
    SQL——事务
      会发现B窗口执行操作时会卡住不执行,这是因为在执行事务期间,一个或多个资源被其他会话锁定。默认情况下,数据库会在卡住一段时间后提示ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction。这就是在一个事务中更新一条记录,但在这个事务还没有提交之前,另一个事务也想要更新同一行记录。那么这个请求就会导致锁等待,如果等待时间超过了系统设置的时间限制,则会出现“Lock wait timeout exceeded”的错误提示。这个错误通常意味着当前事务需要等待其他正在运行的事务释放锁定的资源。
    Repeatable Read级别窗口A
    -- 提交事务
    commit;
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    4 | tian |  9000 |
    |    5 | 369  | 12000 |
    +------+------+-------+
    3 rows in set (1.02 sec)
    
    Serializable级别窗口B
    -- 查询数据
    select * from account;
    -- 结果
    +------+------+-------+
    | id   | name | money |
    +------+------+-------+
    |    1 | ning |  8000 |
    |    4 | tian |  9000 |
    |    5 | 369  | 12000 |
    +------+------+-------+
    3 rows in set (1.02 sec)
    
      会发现,在B窗口执行查询语句卡住的时候,将A窗口的操作提交,B窗口会随之立刻执行查询语句,这是因为在串行化隔离级别下,所有的事务都是一个接一个地执行,不会有两个事务同时并发访问同一组数据的情况出现,因此能保证查询结果的准确性和一致性。因此不会出现幻读和不可重复读的问题。

🔥 设置隔离

  1. 查看当前会话隔离级别
    select @@transaction_isolation;
    
  2. 查看当前系统隔离级别
    select @@global.transaction_isolation;
    
  3. 设置当前会话隔离级别
    -- <isolation_level> 表示要设置的隔离级别,
    -- 可以是 READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE 中的任意一个。
    SET SESSION TRANSACTION ISOLATION LEVEL <isolation_level>;
    
  4. 设置当前系统隔离级别
    -- <isolation_level> 表示要设置的隔离级别
    -- 可以是 READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE 中的任意一个。
    SET GLOBAL TRANSACTION ISOLATION LEVEL <isolation_level>;
    
  5. mysql默认的事务隔离级别是REPEATABLE-READ,一般情况下,没有要求,没必要修改。
    -- 全局修改,修改mysql.ini配置文件,在最后加上:
    -- 可以是 READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE 中的任意一个。
    [mysqld]
    transaction-isolation=REPEATABLE-READ
    

到了这里,关于SQL——事务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【基础7】SQL事务及触发器

    目录 事务(TRANSACTION) 触发器 DML触发器 DDL触发器 触发器的练习 什么是事务 事务是作为单个逻辑工作单元执行的一系列操作,它包含了一组数据库操作命令 所有的操作命令作为一个整体一起向系统提交,要么都执行、要么不执行 事是SQL Server 中执行并发控制的基本单位,是

    2024年02月06日
    浏览(33)
  • SQL Developer 默认是不会自动提交事务

    SQL Developer这软件,在执行数据库数据修改操作时,并不会进行SQL提交。 SQL Developer默认是不会进行自动提交,必须通过手动的方式提交。 如:

    2024年02月13日
    浏览(36)
  • Sql Server 数据库事务与锁,同一事务更新又查询锁?期望大家来解惑

    我有一个People表,有三行数据: 如果我们没详细了解数据库事务执行加锁的过程中,会不会有这样一个疑问:如下的这段 SQL 开启了事务,并且在事务中进行了更新和查询操作。 我们知道sql server数据库的默认事务级别是READ COMMITTED(已提交的读取),我们再看一下已提交读事

    2024年02月01日
    浏览(45)
  • 【建议收藏】数据库 SQL 入门——事务(内附演示)

    🙋‍♂️作者简介:生鱼同学,大数据科学与技术专业硕士在读👨‍🎓,曾获得华为杯数学建模国家二等奖🏆,MathorCup 数学建模竞赛国家二等奖🏅,亚太数学建模国家二等奖🏅。 ✍️研究方向:复杂网络科学 🏆兴趣方向:利用python进行数据分析与机器学习,数学建模竞

    2023年04月23日
    浏览(30)
  • SQL Server 事务日志文件过大 解决方案

    事务日志文件(Transaction Log File)是用来记录数据库更新情况的文件,扩展名为ldf。当出现以下情况时,就会报“ 事务日志已满 ”的错误: 日志文件没有设置了自动增长,当记录超过初始大小; 日志文件设置了自动增长,“最大文件大小”设置了具体的大小(如2000M),当

    2024年02月10日
    浏览(39)
  • Sql Server 数据库事务与锁,同一事务更新又查询锁的变化,期望大家来解惑!

    我有一个People表,有三行数据: 如果我们没详细了解数据库事务执行加锁的过程中,会不会有这样一个疑问:如下的这段 SQL 开启了事务,并且在事务中进行了更新和查询操作。 我们知道sql server数据库的默认事务级别是READ COMMITTED(已提交的读取),我们再看一下已提交读事

    2024年02月01日
    浏览(59)
  • SQL进阶(2)——SQL语句类型 & 增删改查CRUD & 事务初步 & 表关联关系 & 视图 +索引

    1.SQL语句的类型,数据操作语句,数据查询语句; 2.MySQL的运算符,常用函数,增删改查CRUD语法; 3.数据操作的事务:原子性,一致性,隔离性,持久性; 4.数据库表关联关系,一对一,一对多,多对多; 5.视图,索引; SQL程序语言有四种类型,对数据库的基本操作都属于这

    2024年02月16日
    浏览(33)
  • MySQL中常用查看锁和事务的SQL语句

    当我们在使用MySQL数据库时,了解如何查看锁和事务的状态是非常重要的。这些信息可以帮助我们调试和优化数据库性能,以及解决并发访问的问题。在本博客中,我将介绍一些常用的MySQL查询语句,用于查看锁和事务的状态。 1. 查看当前的锁状态 要查看当前数据库中的锁状

    2024年02月09日
    浏览(30)
  • 「SAP ABAP」OPEN SQL(九)【SAT事务码】

    💂 作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后端的开发语言ABAP,SQL进行任务的完成,对SAP企业管理系统,SAP ABAP开发和数据库具有较

    2023年04月13日
    浏览(37)
  • 读SQL学习指南(第3版)笔记09_条件逻辑与事务

    1.3.1.1. Oracle的decode()函数 1.3.1.2. MySQL的if()函数 1.3.1.3. SQL Server的coalesce()函数 1.3.2.1. 在Oracle Database、SQL Server、MySQL、PostgreSQL、IBM UDB等数据库中实现 1.3.3.1. 用于select、insert、update和delete语句 1.3.4.1. sql 1.3.4.2. mysql 1.3.5.1. simple case expression 1.3.5.2. 类似于搜索型case表达式,但

    2024年02月10日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包