前言
当涉及到数据库并发访问和数据一致性时,MySQL 锁机制发挥着重要的作用。MySQL 提供了不同级别的锁,包括表级锁和行级锁,以及其他类型的锁,用于实现并发控制。本文将详细介绍 MySQL 锁的应用,包括锁的类型、使用场景和示例代码,以帮助读者更好地理解和使用 MySQL 锁。
MySQL锁的详解
1. 表级锁
表级锁适用于对整个表进行锁定,限制对整个表的访问。MySQL 提供了读锁和写锁,分别允许多个会话同时获取读锁,而只允许一个会话获取写锁。
package com.example.onlystudent.mysql.锁; /** * @BelongsProject: OnlyStudent * @BelongsPackage: com.example.onlystudent.mysql.锁 * @Author: gepengjun * @CreateTime: 2023-05-16 08:14 * @Description: 表级锁示例 * @Version: 1.0 */ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class TableLevelLockExample { public static void main(String[] args) { //String url = "jdbc:mysql://localhost:3306/shop"; //String username = "root"; //String mima= ""; try (Connection connection = DriverManager.getConnection(url, username, password)) { connection.setAutoCommit(false); // 事务1获取表级写锁 Statement stmt1 = connection.createStatement(); stmt1.execute("LOCK TABLES shop_product WRITE"); // 事务2尝试获取表级读锁 Statement stmt2 = connection.createStatement(); stmt2.execute("LOCK TABLES shop_product READ"); // 处理数据 // ... //提交事务 connection.commit(); //释放锁 stmt2.execute("UNLOCK TABLES"); } catch (SQLException e) { e.printStackTrace(); } } }
1.1 读锁(共享锁)
读锁,也称为共享锁,允许多个会话同时获取读锁,不阻塞其他会话的读取操作。读锁适用于并发读取数据的场景。
示例代码:
-- 获取读锁 LOCK TABLES table_name READ; -- 执行读取操作 SELECT * FROM table_name; -- 解锁 UNLOCK TABLES;
对比
现在执行java程序,这里执行的是事务二,可以看到事务二是执行的读锁,在执行完读锁后去Navicat中去看看执行一些SQL语句看看效果。
查询操作
可以看到正常的select语句还是可以执行的。
更新操作
这里执行更新操作,可以看到提示“表“shop_product”已被READ锁锁定,无法更新”,这里就不展示删除和添加了,因为它俩和更新都是同类型的,都对表进行了事务级别的操作。所以得到的结果也是无法新增或者删除。因为表已经被锁定了。
获取写锁
执行完LOCK TABLES shop_product WRITE后Navicat一直处理等待中,也就是说当一个事务获取了一张表的读锁时,其它事务就不可以获取这张表的写锁。
获取读锁
可以看到啊,很快啊!
直接获取到这张表的读锁,这也是上面说的它是共享锁。
1.2 写锁(排他锁)
写锁,也称为排他锁,只允许一个会话获取写锁,其他会话无法同时获取读锁或写锁。写锁适用于修改数据的场景,保证数据的一致性。
示例代码:
-- 获取写锁 LOCK TABLES table_name WRITE; -- 执行写入操作 UPDATE table_name SET column_name = value; -- 解锁 UNLOCK TABLES;
对比
获取写锁
在执行Java程序中事务1通过使用表级别的写锁,获取到了shop_product这个表的锁,我在Navicat中同样执行写锁结果却是处于等待状态,在等待这个表的写锁(排它锁)释放。