并发控制
当程序中可能出现并发操作的情况时,就需要保证在并发操作的情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和某个用户单独操作时的结果是一样的。这种手段就叫做并发控制。并发控制的目的是
保证一个用户的操作不会对另一个用户的操作结果产生不合理的影响。
如果没有做好并发控制,就可能导致数据脏读、幻读和不可重复读等问题。
并发控制,一般都和数据库管理系统(DBMS)有关。在 DBMS 中的并发控制的任务,是为了确保在多个事务同时存取数据库中的同一数据时,不破坏事务的隔离性、一致性和数据库的统一性。
实现并发控制的主要手段大致可以分为乐观并发控制 和 悲观并发控制两种。
乐观锁和悲观锁
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。
其实不仅仅是关系型数据库系统中才有乐观锁和悲观锁的概念,像 hibernate、tair、memcache 等都有类似的概念。所以,不应该拿乐观锁、悲观锁和其他的数据库锁等进行对比
import com.shige.JDBC.Utils.DBUtil;
import java.sql.*;
/**
* 事物1
* 演示悲观锁(行级锁)
* 该事务进行查询操作,并使用悲观锁,锁住相关数据
*/
public class JDBCTest10 {
public static void main(String[] args) throws SQLException {
//创建数据库连接所需要的对象‘
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
try {
//获取连接
connection=DBUtil.getConnection();
// 关闭事务自动提交
connection.setAutoCommit(false);
//获取数据库预编译对象
String sql="SELECT ENAME ,JOB,SAL FROM EMP WHERE JOB=? FOR UPDATE";
preparedStatement=connection.prepareStatement(sql);
//给占位符传值
preparedStatement.setString(1,"MANAGER");
//执行SQL
resultSet=preparedStatement.executeQuery();
//处理查询结果集
while(resultSet.next()){
System.out.print(resultSet.getString("ENAME")+" ");
System.out.print(resultSet.getString("JOB")+" ");
System.out.println(resultSet.getString("SAL")+" ");
}
} catch (SQLException e) {
//回滚事务
if(connection!=null){
connection.rollback();
}
e.printStackTrace();
}finally {
//释放资源
DBUtil.close(connection,preparedStatement,resultSet);
}
}
}
// 这是事物2 对事物1锁住的数据进行修改操作。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 演示悲观锁(行级锁)
* 该事务进行修改被上个事务锁住的数据
*/
public class JDBCTest11 {
public static void main(String[] args) throws SQLException {
//创建数据库连接所需要的对象‘
Connection connection=null;
PreparedStatement preparedStatement=null;
int count=0;
try {
//获取连接
connection= DBUtil.getConnection();
// 关闭事务自动提交
connection.setAutoCommit(false);
//获取数据库预编译对象
String sql="UPDATE EMP SET SAL=SAL*2 WHERE JOB=?";
preparedStatement=connection.prepareStatement(sql);
//给占位符传值
preparedStatement.setString(1,"MANAGER");
//执行SQL
count=preparedStatement.executeUpdate();
//输出
System.out.println(count==3?"修改成功":"修改失败");
//手动提交事务
connection.commit();
} catch (SQLException e) {
//回滚事务
if(connection!=null){
connection.rollback();
}
e.printStackTrace();
}finally {
//释放资源
DBUtil.close(connection,preparedStatement,null);
}
}
}