行级锁(悲观锁)的概念
程序员文章站
2024-01-13 15:26:34
...
行级锁(悲观锁)的概念:
怎么样才会产生行级锁?
例如:select ename, job, sal from emp where job = ‘Manager’ for update;
在后面加了for update就产生了行级锁。
行级锁有什么用?
将查询结果集在表中的对应的记录,开始锁住,在当前事务结束前,别的事务根本修改不了锁住的数据。
行级锁也被称为悲观锁。
有悲观锁,就对应有乐观锁,那什么是乐观锁?
乐观锁会在数据后面添加一个隐藏的版本号,假设为version。
只要事务读取到的版本号没有改变,事务就能对数据进行修改。
例如:
假设有两个事务对表中的同一数据进行修改。
事务A:读取到版本号为1.1。
事务B:读取到的版本为1.1。
事务A先修改了数据,并对应的把版本号修改为1.2。
事务B再去修改数据,修改之后发现版本号变成了1.2,与原来读取到的版本不一致,放弃修改,事务回滚。
悲观锁(行级锁):事务必须排队执行,数据被锁住,无法并发执行。
乐观锁:支持并发,事务不需要排队,只不过需要版本号一致。
(1)Test01和Test02共同演示行级锁:
Test01开启一个事务,进行查询,并锁住相应的数据。
测试代码:
import jdbc_util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test01 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1、注册驱动,2、获取连接
conn = DBUtil.getConnection();
// 关闭事务自动提交,开启一个事务
conn.setAutoCommit(false);
// 3、获取预编译数据库操作对象
String sql = "select ename, job, sal from emp where job = ? for update";
ps = conn.prepareStatement(sql);
// 给占位符传值
ps.setString(1, "Manager");
// 4、执行sql语句
rs = ps.executeQuery();
// 将断点打在这,也就是提交事务之前,看Test02运行能否修改锁住的数据
// 5、处理查询结果集
while (rs.next()) {
String ename = rs.getString("ename");
String job = rs.getString("job");
String sal = rs.getString("sal");
System.out.println(ename + "-" + job + "-" + sal);
}
// 手动提交事务,当前事务结束
conn.commit();
} catch (SQLException throwables) {
if (conn != null) {
try {
conn.rollback(); // 出现异常,事务回滚
} catch (SQLException e) {
e.printStackTrace();
}
}
throwables.printStackTrace();
} finally {
// 6、释放资源
DBUtil.close(conn, ps, rs);
}
}
}
(2)Test02程序开启一个事务,去修改被Test01用行级锁(悲观锁)锁住的数据:
测试代码:
import jdbc_util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test02 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 1、注册驱动,2、获取连接
conn = DBUtil.getConnection();
// 关闭事务自动提交,开启一个事务
conn.setAutoCommit(false);
// 3、获取预编译的数据库操作对象
String sql = "update emp set sal = sal + 10 where job = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "Manager");
// 4、执行sql语句
int line = ps.executeUpdate();
System.out.println(line);
// 5、无处理查询结果集
// 手动提交事务,当前事务结束
conn.commit();
} catch (SQLException throwables) {
if (conn != null) {
try {
conn.rollback(); // 出现异常,事务回滚
} catch (SQLException e) {
e.printStackTrace();
}
}
throwables.printStackTrace();
} finally {
// 6、释放资源
DBUtil.close(conn, ps, null);
}
}
}
测试结果:
Test01事务结束之前,Test02事务无法修改被Test01用行级锁锁住的数据。
上一篇: 十三、MySQL数据库的锁,全局锁、表锁和行锁的应用
下一篇: Oracle查看被锁的表和解锁