Mysql数据库高级特性【二】事务和锁

目录

事务

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)


 

事务

1.事务的特性

一组SQL操作,要么全部成功,要么全部失败,用于保证数据的一致性和完整性,支持提交(COMMIT)和回滚(ROLLBACK)

2.ACID(四个基本属性首字母缩写)属性

原子性(Atomicity)

事务被视为最小的不可分割的工作单位,只有事务中所有操作都完成,事务才算成功。如果事务中的任一操作失败,那么整个事务也会失败并且系统会自动撤销或回滚事务的所有操作,保持数据的一致性。

一致性(Consistency)

事务必须保证它在不破坏数据库的完整性和约束的前提下执行。在事务开始之前和结束之后,数据库必须保持一致状态。

隔离性(lsolation)

事务在提交之前,对其它事务是不可见的。这是为了防止多个并发事务相互干扰。依赖于隔离级别,事务可能会"看到"其他并非提交的事务所做的改动,反之亦然。MySQL提供不同的隔离级别如READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ (默认的隔离级别), 和SERIALIZABLE。

隔离性确保并发执行的事务之间互不影响,每个事务独立于其他事务进行,防止“脏读”、“不可重复读”和“幻读”等问题

持久性(Durability)

一旦事务提交,其所做的改动就会被永久保存在数据库中,即使数据库系统发生故障也不会丢失这些改动。

3.事务的操作

开始事务

MariaDB [(none)]>Start transaction;
  1. 插入

INSERT INTO users (username) VALUES ('john_doe');

#在"users"表的"username"列中插入一个新的数据行,其中"username"的值为"john_doe"

2.更新

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

3.保存点

Savepoint my_savepoint; 

#在事务中设置一个保存点,允许你在事务的不同阶段进行部分提交或回滚

4.提交事务

COMMIT;
  1. 回滚事务

ROLLBACK;

 #撤销事务中的所有操作

ROLLBACK TO SAVEPOINT my_savepoint;

#回滚到特定的保存点

6.自动提交控制

MySQL默认情况下是自动提交模式,每条语句都会被当作一个单独的事务处理。你可以使用 SET autocommit 命令来改变这个行为

SET autocommit = 0;

#关闭自动提交

SET autocommit = 1;

#开启自动提交

4.事务编写案例(银行账户转账)

1.创建数据库

Create database bank;

2.创建数据表

CREATE TABLE accounts (

    account_number INT PRIMARY KEY,

    account_name VARCHAR(100),

    balance DECIMAL(15, 2)         #保留两位小数的余额

);

3.逻辑分析

  • 开始一个新的事务
  • 检查源账户的余额是否足够进行转账
  • 从源账户扣除转账金额
  • 向目的账户添加转账金额
  • 如果所有步骤都成功,则提交事务,如果有任何一步失败,则回滚事务以撤销所有更改

4.编写脚本

-- 开始事务

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;

 

1.锁的特性

是一种用于控制并发访问和修改数据的技术。锁可以确保在同一时间只能有一个事务对特定数据进行访问和修改,从而避免数据不一致和冲突

2.类型

共享锁(S锁)

当一个事务对某一行数据进行读取时,会自动获取该行的共享锁。其他事务在查询该行数据时,也会获取共享锁。共享锁允许多个事务同时读取同一行数据,但阻止了对数据的修改。当第一个事务释放锁时,其他事务也可以释放锁

排他锁(X锁)

当一个事务要对某一行数据进行修改时,它需要获取该行的排他锁。排他锁阻止其他事务对该行数据进行读取和修改,确保锁期间只有持有锁的事务可以对数据进行操作。当持有排他锁的事务完成操作并释放锁后,其他事务才能获取锁并进行相应操作。

3.锁的概念

锁的分级:mysql中的锁分为表层锁(table locks)和行层锁(row locaks)。表层锁用于锁定整个表,而行层锁用于锁定特定行。在实际操作中,行层锁更加细粒度,可以避免锁冲突,提高并发性能。

锁的兼容性:不同类型的锁之间有一定的兼容性。共享锁和排他锁在某些情况下可以同时存在,例如在更新数据时,更新事务会持有排他锁,同时其他事务可以获取共享锁。

锁的自动释放:mysql的锁在事务提交或回滚时会自动释放,这意味着当事务完成操作后,锁会被自动释放,其他事务可以获取锁并进行操作

锁的优点和缺点:锁可以确保数据的一致性和完整性,但同时也会引入一定的性能开销。在并发访问较高的场景下,锁可能导致锁等待和事务阻塞,降低系统性能。因此,在实际应用中,需要权衡并发性能和数据一致性之间的关系,合理配置锁参数。

4.配置和使用

锁的类型选择

根据业务需求和并发访问情况,选择合适的锁类型。共享锁适合读多写少的场景,而排他锁适合读写冲突较多的场景。

可以使用`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`参数来控制事务在等待锁的时间上限。超过该时间后,事务会抛出锁等待超时的异常。适当的设置等待超时时间可以避免事务阻塞过长时间,影响其他并发操作。

优化锁的操作

在实际编程中,可以优化锁的获取和释放策略,减少锁等待和阻塞的时间。例如,尽可能减小事务的范围和持有锁的时间,避免不必要的锁操作,合理使用索引和优化查询语句等。

  1. 相关命令

    全局锁(Flush Tables with Read Lock)

#用于对整个MySQL实例加全局读锁,阻止所有数据定义语言(DDL)和数据修改语言(DML)的操作

FLUSH TABLES WITH READ LOCK;

        解锁(Unlock Tables)

  #解除之前通过FLUSH TABLES WITH READ LOCK命令设置的全局读锁。

UNLOCK TABLES;

        表级锁(table locks)

#可以在事务开始时显示的获取和释放

LOCK TABLES table_name READ; 

#获取表级读锁

LOCK TABLES table_name WRITE; 

#获取表级写锁

UNLOCK TABLES;

#解锁表

行级锁(Row Locks)

行级锁通常由数据库引擎(如InnoDB)自动管理,而不是通过明确的命令来获取和释放。但是,可以通过以下方式影响行锁的行为

使用SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE语句在查询时获取行锁:

SELECT * FROM table_name WHERE condition FOR UPDATE;

元数据锁(Metadata Locks, MDL)

元数据锁是MySQL自动管理的,用于保护数据字典的完整性。这些锁在执行DDL操作时自动获取和释放,通常不需要用户干预

(注:不同的MySQL存储引擎可能支持不同类型的锁,例如MyISAM不支持行锁,而InnoDB支持行锁。在使用锁时,应考虑到并发性和性能的影响,并确保在完成事务后正确释放锁)

 

你可能感兴趣的:(mysql,数据库,linux,运维,缓存)