目录
事务
1.事务的特性
2.ACID(四个基本属性首字母缩写)属性
原子性(Atomicity)
一致性(Consistency)
隔离性(lsolation)
持久性(Durability)
3.事务的操作
开始事务
插入
2.更新
3.保存点
4.提交事务
回滚事务
6.自动提交控制
4.事务编写案例(银行账户转账)
1.创建数据库
2.创建数据表
3.逻辑分析
4.编写脚本
锁
1.锁的特性
2.类型
共享锁(S锁)
排他锁(X锁)
3.锁的概念
4.配置和使用
锁的类型选择
锁的并发控制
锁的监控和诊断
锁的粒度控制
锁的等待超时设置
优化锁的操作
相关命令
全局锁(Flush Tables with Read Lock)
解锁(Unlock Tables)
表级锁(table locks)
行级锁(Row Locks)
元数据锁(Metadata Locks, MDL)
一组SQL操作,要么全部成功,要么全部失败,用于保证数据的一致性和完整性,支持提交(COMMIT)和回滚(ROLLBACK)
事务被视为最小的不可分割的工作单位,只有事务中所有操作都完成,事务才算成功。如果事务中的任一操作失败,那么整个事务也会失败并且系统会自动撤销或回滚事务的所有操作,保持数据的一致性。
事务必须保证它在不破坏数据库的完整性和约束的前提下执行。在事务开始之前和结束之后,数据库必须保持一致状态。
事务在提交之前,对其它事务是不可见的。这是为了防止多个并发事务相互干扰。依赖于隔离级别,事务可能会"看到"其他并非提交的事务所做的改动,反之亦然。MySQL提供不同的隔离级别如READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ (默认的隔离级别), 和SERIALIZABLE。
隔离性确保并发执行的事务之间互不影响,每个事务独立于其他事务进行,防止“脏读”、“不可重复读”和“幻读”等问题
一旦事务提交,其所做的改动就会被永久保存在数据库中,即使数据库系统发生故障也不会丢失这些改动。
MariaDB [(none)]>Start transaction;
INSERT INTO users (username) VALUES ('john_doe');
#在"users"表的"username"列中插入一个新的数据行,其中"username"的值为"john_doe"
UPDATE orders SET user_id = LAST_INSERT_ID() WHERE order_id = 123;
#在"orders"表中,找到"order_id"为123的记录,然后将其"user_id"列的值设置为最近一次自动增长字段插入操作生成的ID
#SET user_id = LAST_INSERT_ID(): 指定要更新的列和新的值,ST_INSERT_ID()是一个MySQL内置函数,它返回最近一次自动增长字段(如自增主键)插入操作生成的ID
Savepoint my_savepoint;
#在事务中设置一个保存点,允许你在事务的不同阶段进行部分提交或回滚
COMMIT;
ROLLBACK;
#撤销事务中的所有操作
ROLLBACK TO SAVEPOINT my_savepoint;
#回滚到特定的保存点
MySQL默认情况下是自动提交模式,每条语句都会被当作一个单独的事务处理。你可以使用 SET autocommit 命令来改变这个行为
SET autocommit = 0;
#关闭自动提交
SET autocommit = 1;
#开启自动提交
Create database bank;
CREATE TABLE accounts (
account_number INT PRIMARY KEY,
account_name VARCHAR(100),
balance DECIMAL(15, 2) #保留两位小数的余额
);
- 开始一个新的事务
- 检查源账户的余额是否足够进行转账
- 从源账户扣除转账金额
- 向目的账户添加转账金额
- 如果所有步骤都成功,则提交事务,如果有任何一步失败,则回滚事务以撤销所有更改
-- 开始事务
START TRANSACTION;
-- 源账户相关信息(例如,从账户 '12345' 转账 '1000')
SET @sourceAccountNumber = 12345;
SET @transferAmount = 1000.00;
-- 目标账户相关信息(例如,向账户 '67890' 转账)
SET @destinationAccountNumber = 67890;
-- 检查源账户的余额是否充足
SELECT @sourceBalance := balance FROM accounts WHERE account_number = @sourceAccountNumber;
IF @sourceBalance < @transferAmount THEN
-- 余额不足,回滚事务
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient funds';
END IF;
-- 扣除源账户金额
UPDATE accounts SET balance = balance - @transferAmount WHERE account_number = @sourceAccountNumber;
-- 增加目的账户金额
UPDATE accounts SET balance = balance + @transferAmount WHERE account_number = @destinationAccountNumber;
-- 提交事务
COMMIT;
是一种用于控制并发访问和修改数据的技术。锁可以确保在同一时间只能有一个事务对特定数据进行访问和修改,从而避免数据不一致和冲突
当一个事务对某一行数据进行读取时,会自动获取该行的共享锁。其他事务在查询该行数据时,也会获取共享锁。共享锁允许多个事务同时读取同一行数据,但阻止了对数据的修改。当第一个事务释放锁时,其他事务也可以释放锁
当一个事务要对某一行数据进行修改时,它需要获取该行的排他锁。排他锁阻止其他事务对该行数据进行读取和修改,确保锁期间只有持有锁的事务可以对数据进行操作。当持有排他锁的事务完成操作并释放锁后,其他事务才能获取锁并进行相应操作。
锁的分级:mysql中的锁分为表层锁(table locks)和行层锁(row locaks)。表层锁用于锁定整个表,而行层锁用于锁定特定行。在实际操作中,行层锁更加细粒度,可以避免锁冲突,提高并发性能。
锁的兼容性:不同类型的锁之间有一定的兼容性。共享锁和排他锁在某些情况下可以同时存在,例如在更新数据时,更新事务会持有排他锁,同时其他事务可以获取共享锁。
锁的自动释放:mysql的锁在事务提交或回滚时会自动释放,这意味着当事务完成操作后,锁会被自动释放,其他事务可以获取锁并进行操作
锁的优点和缺点:锁可以确保数据的一致性和完整性,但同时也会引入一定的性能开销。在并发访问较高的场景下,锁可能导致锁等待和事务阻塞,降低系统性能。因此,在实际应用中,需要权衡并发性能和数据一致性之间的关系,合理配置锁参数。
根据业务需求和并发访问情况,选择合适的锁类型。共享锁适合读多写少的场景,而排他锁适合读写冲突较多的场景。
可以使用`SELECT ... FOR SHARE`语句获取共享锁,使用`SELECT ... FOR UPDATE`语句获取排他锁
通过设置事务的隔离级别来控制并发访问的锁行为。MySQL提供了四种隔离级别:未提交读(Read Uncommitted)、提交读(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。较高的隔离级别会引入更多的锁和资源消耗,需要根据实际需求进行选择。
MySQL提供了一些诊断工具和日志信息,可以用于监控和诊断锁相关的问题。例如,可以使用`SHOW PROCESSLIST`命令查看当前的事务和锁信息,使用`SHOW ENGINE INNODB STATUS`命令查看InnoDB引擎的状态和锁等信息。
根据应用的特点选择表层锁还是行层锁。表层锁可以锁定整个表,适用于大规模并发访问的情况。行层锁可以避免锁冲突,提高并发性能,适用于针对特定行的操作。
可以通过设置`innodb_lock_wait_timeout`参数来控制事务在等待锁的时间上限。超过该时间后,事务会抛出锁等待超时的异常。适当的设置等待超时时间可以避免事务阻塞过长时间,影响其他并发操作。
在实际编程中,可以优化锁的获取和释放策略,减少锁等待和阻塞的时间。例如,尽可能减小事务的范围和持有锁的时间,避免不必要的锁操作,合理使用索引和优化查询语句等。
#用于对整个MySQL实例加全局读锁,阻止所有数据定义语言(DDL)和数据修改语言(DML)的操作
FLUSH TABLES WITH READ LOCK;
#解除之前通过FLUSH TABLES WITH READ LOCK命令设置的全局读锁。
UNLOCK TABLES;
#可以在事务开始时显示的获取和释放
LOCK TABLES table_name READ;
#获取表级读锁
LOCK TABLES table_name WRITE;
#获取表级写锁
UNLOCK TABLES;
#解锁表
行级锁通常由数据库引擎(如InnoDB)自动管理,而不是通过明确的命令来获取和释放。但是,可以通过以下方式影响行锁的行为
使用SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE语句在查询时获取行锁:
SELECT * FROM table_name WHERE condition FOR UPDATE;
元数据锁是MySQL自动管理的,用于保护数据字典的完整性。这些锁在执行DDL操作时自动获取和释放,通常不需要用户干预
(注:不同的MySQL存储引擎可能支持不同类型的锁,例如MyISAM不支持行锁,而InnoDB支持行锁。在使用锁时,应考虑到并发性和性能的影响,并确保在完成事务后正确释放锁)