Java 和 数据库进行加锁方式

 

1.java方式:

publicstatic synchronized int generate(StringtableName){  
  Stringsql = "select value from t_table_id where table_name=?";  
  Connectionconn = null;  
  PreparedStatementpstmt = null;  
  ResultSetrs = null;  
  intvalue = 0;  
  try{  
    conn= DbUtil.getConnection();  
    pstmt= conn.prepareStatement(sql);  
    pstmt.setString(1,tableName);  
    rs= pstmt.executeQuery();  
    rs.next();  
//                        if(!rs.next()){  
//                                thrownew RuntimeException();  
//                        }  
  value= rs.getInt("value");  
  value++;  
  modifyValueField(conn,tableName,value);  
}catch(Exceptione){  
  e.printStackTrace();  
  thrownew RuntimeException();  
}finally{  
    DbUtil.close(rs);  
    DbUtil.close(pstmt);  
    DbUtil.close(conn);  
}  
  returnvalue;  
}  

2.数据库的方式:

//采用悲观锁来实现同步  
//在sql语句后加 for update就加上了锁,在查询的时候进行加锁,在加锁后不能进行查询。提交时候后其他人才能查询。  
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();  
            //设置自动提交为false  
            DbUtil.beginTransaction(conn);  
            pstmt = conn.prepareStatement(sql);  
            pstmt.setString(1, tableName);  
            rs = pstmt.executeQuery();  
            rs.next();  
//          if(!rs.next()){  
//              throw new RuntimeException();  
//          }  
            value = rs.getInt("value");  
            value++;  
            modifyValueField(conn,tableName,value);  
            //提交事务  
            DbUtil.commitTransaction(conn);  
        }catch(Exception e){  
            e.printStackTrace();  
            //回滚事务  
            DbUtil.rollbackTranscation(conn);  
            throw new RuntimeException();  
        }finally{  
            DbUtil.close(rs);  
            DbUtil.close(pstmt);  
            DbUtil.resetConnection(conn);  
            DbUtil.close(conn);  
        }  
        return value;  
    }  

3.数据库乐观锁

乐观锁通常实现基于数据版本(version)的记录机制实现的,比如有一张红包表(t_bonus),有一个字段(left_count)记录礼物的剩余个数,用户每领取一个奖品,对应的left_count减1,在并发的情况下如何要保证left_count不为负数,乐观锁的实现方式为在红包表上添加一个版本号字段(version),默认为0。

异常实现流程

-- 可能会发生的异常情况
-- 线程1查询,当前left_count为1,则有记录
select * from t_bonus where id = 10001 and left_count > 0

-- 线程2查询,当前left_count为1,也有记录
select * from t_bonus where id = 10001 and left_count > 0

-- 线程1完成领取记录,修改left_count为0,
update t_bonus set left_count = left_count - 1 where id = 10001

-- 线程2完成领取记录,修改left_count为-1,产生脏数据
update t_bonus set left_count = left_count - 1 where id = 10001

通过乐观锁实现


-- 添加版本号控制字段
ALTER TABLE table ADD COLUMN version INT DEFAULT '0' NOT NULL AFTER t_bonus;

-- 线程1查询,当前left_count为1,则有记录,当前版本号为1234
select left_count, version from t_bonus where id = 10001 and left_count > 0

-- 线程2查询,当前left_count为1,有记录,当前版本号为1234
select left_count, version from t_bonus where id = 10001 and left_count > 0

-- 线程1,更新完成后当前的version为1235,update状态为1,更新成功
update t_bonus set version = 1235, left_count = left_count-1 where id = 10001 and version = 1234

-- 线程2,更新由于当前的version为1235,udpate状态为0,更新失败,再针对相关业务做异常处理
update t_bonus set version = 1235, left_count = left_count-1 where id = 10001 and version = 1234

猜你喜欢

转载自blog.csdn.net/qq_30509055/article/details/85340954