在上一篇博客中说到Java中的synchronized关键字,它在处理高并发的时候对代码加了锁,但是并不能保证数据的一致性。这个时候我们可以用悲观锁。
悲观锁,正如其名,悲观!以为别人一上来就要修改数据库,所以它就从别人一上来的时候对数据加锁了!它具有强烈的独占和排他特性,对于外界的修改持一种保守的态度,所以每次拿数据的时候都会上锁,也就是在操作之前上锁。
示例:
<span style="font-family:KaiTi_GB2312;font-size:24px;"><span style="font-family:KaiTi_GB2312;font-size:24px;">
public static int generate(String tableName){
//使用数据库的悲观锁for update
String sql = "select value from t_table_id where table_name=? for update";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int value = 0;
try{
conn = DbUtil.getConnection();
//执行事务
DbUtil.beginTransaction(conn);
pstmt = conn.prepareStatement(sql);
pstmt.setString(1,tableName);
rs = pstmt.executeQuery();
if (!rs.next()){
throw new RuntimeException();
}
value = rs.getInt("value");
value++;//自加
modifyValueField(conn, tableName,value);
//提交事务
DbUtil.commitTransactin(conn);
}catch(Exception e){
e.printStackTrace();
//回滚事务
DbUtil.rollbackTransaction(conn);
throw new RuntimeException();
}finally{
DbUtil.close(rs);
DbUtil.close(pstmt);
DbUtil.resetConnection(conn);//重置Connection的状态
DbUtil.close(conn);
}
return value;
}</span></span>
<span style="font-family:KaiTi_GB2312;font-size:24px;"> public static void beginTransaction(Connection conn){//开始事务
try {
if (conn !=null){
if (conn.getAutoCommit()){
conn.setAutoCommit(false);//手动提交
}
}
}catch(SQLException e){}
}
public static void commitTransactin(Connection conn){//提交事务
try{
if(conn !=null){
if(!conn.getAutoCommit()){
conn.commit();
}
}
}catch(SQLException e){}
}
public static void rollbackTransaction(Connection conn){//事物回滚
try{
if (conn !=null){
if (conn.getAutoCommit()){
conn.setAutoCommit(false);
}else{
conn.setAutoCommit(true);
}
}
}
catch(SQLException e){}
}
public static void resetConnection(Connection conn){//事物重置
try{
if(conn != null){
if(conn.getAutoCommit()){
conn.setAutoCommit(false);
}else{
conn.setAutoCommit(true);
}
}
}catch(SQLException e){}
}</span>
悲观锁的实现,往往依靠数据库提供的锁机制,这也就说明了只有在数据库层提供的锁机制才能正真保证数据访问的排他性。
与悲观锁相对应的是乐观锁,乐观锁以为别人上来不会修改数据,所以它是没有加锁的,只有在更新的时候才会判断别人有没有更新这个数据库。