指一组sq语句
用于关系数据库的,避免发生意外时数据的不一致
特点:Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)

创建事务

  1. USE sql_store;
  2. START TRANSACTION;
  3. --
  4. INSERT INTO orders(customer_id,order_date,status)
  5. VALUES (2,'2022-1-1',2);
  6. --
  7. INSERT INTO order_items
  8. VALUES (last_insert_id(),3,3,3);
  9. COMMIT;

如果①执行了但中途断开链接了,②还没执行,则①同样也不会执行
提交COMMIT:将未储存的sql语句结果写入数据库
回退ROLLBACK:撤销指定sql语句,例如INSERT,UPDATE,DELETE语句

并发和锁定

并发:多个用户同时访问处理数据库
锁定:用户A执行了事务中的代码但还未执行到提交时,用户B若同时处理这个数据,当执行到处理代码时,会一直转圈最后加载超时,因为此时该数据正在被A执行,已被锁定,当A执行COMMIT代码后,B才可以继续执行
默认情况下,MYSQL会对同时处理的数据上锁

并发问题和隔离级别

image.png
MySQL默认的隔离级别为REPEATABLE READ
越往下隔离级别越高,发生并发问题越少,但同时需要更多的锁,需要更多的资源,可能会损伤性能和扩展性

查看和更改隔离级别

image.png
SESSION表示未来的事务都采用这个隔离级别,若没有SESSION则表示下一个采用这个隔离级别

READ UNCOMMITTED读取未提交隔离级别

初始情况
image.png
用户A执行到commit语句之前时

  1. USE sql_store;
  2. START TRANSACTION;
  3. UPDATE customers
  4. SET points = 30
  5. WHERE customer_id = 1;
  6. COMMIT;

用户B查询结果为
image.png
但A此时查询的结果为
image.png
两者不一致,出现脏读(Dirty Reads)并发问题!

READ COMMITTED读已提交隔离级别

这一隔离级别不存在脏读,但存在不可重复读

  1. USE sql_store;
  2. SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  3. START transaction;
  4. SELECT points FROM customers WHERE customer_id = 1;
  5. SELECT points FROM customers WHERE customer_id = 1;
  6. COMMIT;

A执行第四行代码时
points = 20
B执行并提交points = 30 的事务
A继续·执行第五行代码时
points = 30
两者不一致

REPEATABLE READ 可重复读隔离级别

这能解决数据不一致问题

  1. USE sql_store;
  2. SET TRANSACTION ISOLATION LEVEL repeatable read;
  3. START transaction;
  4. SELECT points FROM customers WHERE customer_id = 1;
  5. SELECT points FROM customers WHERE customer_id = 1;
  6. COMMIT;

A执行第四行代码
此时显示points = 40
B执行并提交points· = 50 的事务
A再执行第五行代码
但依旧显示points= 40而不是 50
但这个还有个问题,幻读,即可能漏掉或多出某部分数据

SERIALIZABLE序列化隔离级别

所有事务按照先后顺序进行,下一个事务需要等待(转圈)上一个事务结束才能执行,就像单用户系统,解决所有的并发问题
用户越多,发生在同时的请求越多,就需要更漫长的等待

Deadlock死锁

  1. USE sql_store;
  2. START TRANSACTION ;
  3. UPDATE customers SET state = 'VA' WHERE customer_id = 3;
  4. UPDATE orders SET status = 1 WHERE order_id = 2;
  5. commit;
  1. USE sql_store;
  2. START TRANSACTION ;
  3. UPDATE orders SET status = 1 WHERE order_id = 2;
  4. UPDATE customers SET state = 'VA' WHERE customer_id = 3;
  5. commit;

A按照顺序运行1123行代码,B运行1233行代码,第四行是进入等待,A再运行第四行代码,又进入等待,出现死锁
注意

  1. 事务里语句的顺序,在更新多条记录的时候,应遵循相同的顺序,顺序相反的话很有可能出现死锁
  2. 简化事务,缩小事务运行时长
  3. 当表很大时,事务可能需要很长的时间来运行,就会有冲突的风险,此时可以将事务安排在非高峰时段运行,避开大量活跃用户