首先什么是悲观锁呢?
如果一个查询语句后面加了for update,例如select * from emp where job = ‘MANAGER’ for update;,当这个SQL语句执行的时候,在事务没有结束之前,job = 'MANAGER’的记录会被锁定,其他事务不能对job = 'MANAGER’进行update操作,这种机制被称为“行级锁”,也被称为悲观锁,锁定的是表中的某些行数据,注意数据库的存储引擎需要使用InnoDB方式;既然说到了悲观锁,这里也说一下乐观锁,乐观锁是可以使用版本号的方式来实现,就是给表上设置一个版本号,多个事务同时进行,当其中一个事务完成之后就会把版本号改变,然后其他的事务在提交的时候发现版本号改变了,就会回滚,这个就是乐观锁,对比来看,悲观锁就是我锁住了,谁都不能动这些记录,而乐观锁是大家都可以动,谁的速度快谁就可以执行命令
使用for update的悲观锁代码:
public class PessimisticLOCK {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet res = null;
try {
ResourceBundle rb = ResourceBundle.getBundle("resource/db");
// 1、注册驱动
String driver = rb.getString("driver");
Class.forName(driver);
// 2、获取连接
String url = rb.getString("url");
String user = rb.getString("user");
String password = rb.getString("password");
conn = DriverManager.getConnection(url, user,password );
conn.setAutoCommit(false);// 设置事务提交方式是手动提交
// 3、获取预编译的数据库操作对象
String sql = "select * from emp where job = ? for update";
ps = conn.prepareStatement(sql);
ps.setString(1, "MANAGER");
// 4、执行SQL
res = ps.executeQuery();
// 5、处理查询结果集
while (res.next()){
System.out.println(res.getString("ename")+","+res.getString("sal"));
}
conn.commit();// 如果没有出现异常,就提交事务
} catch (ClassNotFoundException e) {
if (conn!=null){
try {
conn.rollback();// 如果出现异常,就回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (res!=null){
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
验证悲观锁的更新代码:
public class CheckLock {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
ResourceBundle rb = ResourceBundle.getBundle("resource/db");
// 1、注册驱动
String driver = rb.getString("driver");
Class.forName(driver);
// 2、获取连接
String url = rb.getString("url");
String user = rb.getString("user");
String password = rb.getString("password");
conn = DriverManager.getConnection(url, user,password );
conn.setAutoCommit(false);// 设置事务提交方式是手动提交
// 3、获取预编译的数据库操作对象
String sql = "update emp set sal=sal*2 where job = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "MANAGER");
// 4、执行SQL
int i = ps.executeUpdate();
System.out.println("更新了"+i+"条");
conn.commit();// 如果没有出现异常,就提交事务
} catch (ClassNotFoundException e) {
if (conn!=null){
try {
conn.rollback();// 如果出现异常,就回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
解释:
在第一个代码中的commit()方法上面设立断点,采用Debug方式运行程序,然后在运行第二个代码,发现第二个代码在等待,然后让第一个代码执行完成,然后第二个代码也会随后执行完成