同样叫 REPEATABLE_READ,PostgreSQL 和 MySQL 的行为一样吗?哪个级别才真的能挡住丢失更新、写偏斜?这篇用两个真实数据库在 JDBC 里逐个构造异常,给出一张实测矩阵。
默认隔离级别:READ_COMMITTED;各级别 supportsTransactionIsolationLevel:[READ_UNCOMMITTED=true, READ_COMMITTED=true, REPEATABLE_READ=true, SERIALIZABLE=true] 设置的级别 脏读 不可重复读 幻读 丢失更新(先读后写) 写偏斜(两人都值班时各自下班) READ_UNCOMMITTED 没有(读到 100) 发生(100 → 500) 发生(2 → 3) t1 提交成功;t2 提交成功;最终余额 110(丢失更新) 最后值班人数 0(两个人都下班了:写偏斜) READ_COMMITTED 没有(读到 100) 发生(100 → 500) 发生(2 → 3) t1 提交成功;t2 提交成功;最终余额 110(丢失更新) 最后值班人数 0(两个人都下班了:写偏斜) REPEATABLE_READ 没有(读到 100) 没有(两次都是 100) 没有(两次都是 2) t1 提交成功;t2 PSQLException(40001) ERROR: could not serialize access due to concurrent update;最终余额 110(有一方失败) 最后值班人数 0(两个人都下班了:写偏斜) SERIALIZABLE 没有(读到 100) 没有(两次都是 100) 没有(两次都是 2) t1 提交成功;t2 PSQLException(40001) ERROR: could not serialize access due to concurrent update;最终余额 110(有一方失败) 最后值班人数 1;t1:ok t2:提交失败 PSQLException(40001) ERROR: could not serialize access due to read/write dependencies among
默认隔离级别:REPEATABLE_READ;各级别 supportsTransactionIsolationLevel:[READ_UNCOMMITTED=true, READ_COMMITTED=true, REPEATABLE_READ=true, SERIALIZABLE=true] 设置的级别 脏读 不可重复读 幻读 丢失更新(先读后写) 写偏斜(两人都值班时各自下班) READ_UNCOMMITTED 发生(读到 999) 发生(100 → 500) 发生(2 → 3) t1 提交成功;t2 提交成功;最终余额 110(丢失更新) 最后值班人数 0(两个人都下班了:写偏斜) READ_COMMITTED 没有(读到 100) 发生(100 → 500) 发生(2 → 3) t1 提交成功;t2 提交成功;最终余额 110(丢失更新) 最后值班人数 0(两个人都下班了:写偏斜) REPEATABLE_READ 没有(读到 100) 没有(两次都是 100) 没有(两次都是 2) t1 提交成功;t2 提交成功;最终余额 110(丢失更新) 最后值班人数 0(两个人都下班了:写偏斜) SERIALIZABLE t2 的读被阻塞:异常:MySQLTransactionRollbackException(40001) Lock wait timeout exceeded; try restarting transaction 没有(t2 的写被阻塞:异常:MySQLTransactionRollbackException(40001) Lock wait timeout exceeded; try restarting transaction) 没有(t2 的插入被阻塞:异常:MySQLTransactionRollbackException(40001) Lock wait timeout exceeded; try restarting transaction) t1 MySQLTransactionRollbackException(40001) Lock wait timeout exceeded; try restarting transaction;t2 MySQLTransactionRollbackException(40001) Lock wait timeout exceeded; try restarting transaction;最终余额 100(有一方失败) 最后值班人数 1;t1:ok t2:MySQLTransactionRollbackException(40001) Deadlock found when trying to get lock; try restarting transaction