天河应用大讲堂 | AI地学大模型的发展:从天气到气候
2026/6/11 21:00:52
-- 显式加共享锁SELECT*FROMtableWHEREid=1LOCKINSHAREMODE;-- 显式加排它锁SELECT*FROMtableWHEREid=1FORUPDATE;| 当前锁状态 | 共享锁(S) | 排它锁(X) | 无锁 |
|---|---|---|---|
| 共享锁(S) | ✅ 兼容 | ❌ 冲突 | ✅ 兼容 |
| 排它锁(X) | ❌ 冲突 | ❌ 冲突 | ✅ 兼容 |
| 无锁 | ✅ 兼容 | ✅ 兼容 | ✅ 兼容 |
-- 场景1:读取数据并确保不被修改STARTTRANSACTION;SELECTbalanceFROMaccountsWHEREuser_id=1001LOCKINSHAREMODE;-- 其他事务可以加共享锁读取,但不能修改-- 确保在事务期间余额数据不被更改COMMIT;-- 场景2:检查引用完整性STARTTRANSACTION;-- 检查是否有订单引用此产品SELECTCOUNT(*)FROMordersWHEREproduct_id=500LOCKINSHAREMODE;-- 如果返回0,可以安全删除产品DELETEFROMproductsWHEREid=500;COMMIT;-- 场景1:更新操作(自动加排它锁)STARTTRANSACTION;UPDATEaccountsSETbalance=balance-100WHEREuser_id=1001;-- 其他事务不能读取(取决于隔离级别)或修改此行COMMIT;-- 场景2:悲观锁控制并发STARTTRANSACTION;SELECT*FROMinventoryWHEREproduct_id=2001FORUPDATE;-- 检查库存并更新UPDATEinventorySETquantity=quantity-1WHEREproduct_id=2001;COMMIT;-- 场景3:防止幻读STARTTRANSACTION;SELECT*FROMordersWHEREuser_id=1001ANDstatus='pending'FORUPDATE;-- 在REPEATABLE READ隔离级别下,防止其他事务插入新的pending订单INSERTINTOorders(...)VALUES(...);COMMIT;// 简化的锁结构表示structlock_t{trx_t*trx;// 持有锁的事务lock_rec_t*rec_lock;// 记录锁lock_table_t*table_lock;// 表锁uint32_ttype_mode;// 锁类型和模式// ... 其他字段};structlock_rec_t{space_id_tspace;// 表空间IDpage_no_tpage_no;// 页号uint32_tn_bits;// 锁位图大小byte*bits;// 锁位图,记录哪些记录被锁住};-- 对单条记录加锁SELECT*FROMusersWHEREid=1FORUPDATE;-- 在id=1的记录上加排它锁-- 防止幻读,锁定一个范围SELECT*FROMusersWHEREageBETWEEN20AND30FORUPDATE;-- 锁定age在20-30之间的间隙,防止其他事务插入-- 记录锁 + 间隙锁的组合SELECT*FROMusersWHEREid>100FORUPDATE;-- 锁定id>100的所有现有记录和间隙-- 事务1:转账操作STARTTRANSACTION;-- 对转出账户加排它锁SELECT*FROMaccountsWHEREaccount_no='A001'FORUPDATE;-- 对转入账户加排它锁SELECT*FROMaccountsWHEREaccount_no='B002'FORUPDATE;-- 执行转账UPDATEaccountsSETbalance=balance-100WHEREaccount_no='A001';UPDATEaccountsSETbalance=balance+100WHEREaccount_no='B002';COMMIT;-- 高并发库存管理STARTTRANSACTION;-- 使用排它锁确保库存准确SELECTquantityFROMinventoryWHEREproduct_id=1001FORUPDATE;-- 检查库存IFquantity>=order_quantityTHENUPDATEinventorySETquantity=quantity-order_quantityWHEREproduct_id=1001;COMMIT;ELSEROLLBACK;-- 库存不足处理ENDIF;-- 查看InnoDB锁状态SHOWENGINEINNODBSTATUS\G-- 查看锁信息部分-- 查看当前锁等待SELECT*FROMinformation_schema.INNODB_LOCKS;SELECT*FROMinformation_schema.INNODB_LOCK_WAITS;-- 查看进程和锁信息SHOWPROCESSLIST;-- 设置锁等待超时时间(秒)SETSESSIONinnodb_lock_wait_timeout=50;SETGLOBALinnodb_lock_wait_timeout=50;-- 查看当前配置SHOWVARIABLESLIKE'innodb_lock_wait_timeout';-- 事务1STARTTRANSACTION;UPDATEaccountsSETbalance=balance-100WHEREid=1;-- 锁住id=1UPDATEaccountsSETbalance=balance+100WHEREid=2;-- 等待id=2的锁-- 事务2(同时执行)STARTTRANSACTION;UPDATEaccountsSETbalance=balance-50WHEREid=2;-- 锁住id=2UPDATEaccountsSETbalance=balance+50WHEREid=1;-- 等待id=1的锁-- 死锁发生!-- InnoDB自动检测死锁并回滚代价较小的事务-- 查看最近死锁信息SHOWENGINEINNODBSTATUS\G-- 在LATEST DETECTED DEADLOCK部分查看详情-- 错误处理代码示例(应用程序层面)try:cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")connection.commit()exceptmysql.connector.errors.DatabaseErrorase:if'Deadlock'instr(e):# 死锁发生,重试逻辑time.sleep(0.1)retry_transaction()else: raise-- 1. 尽量使用索引,减少锁范围-- 慢:全表扫描,锁住所有记录SELECT*FROMusersWHEREnameLIKE'%john%'FORUPDATE;-- 快:使用索引,只锁相关记录SELECT*FROMusersWHEREid=1001FORUPDATE;-- 2. 保持事务简短STARTTRANSACTION;-- 尽快完成数据操作UPDATE...;DELETE...;COMMIT;-- 立即提交释放锁-- 3. 按固定顺序访问资源,避免死锁-- 所有事务都按id升序访问账户UPDATEaccountsSET...WHEREid=1;UPDATEaccountsSET...WHEREid=2;-- 4. 使用较低的隔离级别(如READ COMMITTED)减少锁竞争SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;-- 读多写少场景:考虑使用乐观锁SELECTversion,dataFROMtableWHEREid=1;-- 应用程序处理业务逻辑UPDATEtableSETdata=new_data,version=version+1WHEREid=1ANDversion=old_version;-- 如果影响行数为0,说明版本已变化,需要重试-- 写多场景:使用悲观锁但控制粒度-- 使用行级锁而不是表锁SELECT*FROMtableWHEREid=1FORUPDATE;-- 而不是:LOCK TABLES table WRITE;共享锁:
排它锁:
关键要点:
正确使用锁机制可以确保数据一致性,同时最大化系统并发性能。