现在我在项目中遇到了一个比较棘手的问题: 
我们项目后台采用的是Hibernate+Spring+Servlet 
       前台采用的是Ajax异步提交 
项目中有一个模块须保证一个序号的唯一和连续,我们的做法是: 
      删除操作:把删除的序号保存到单独的一张表里。 
      添加操作:先到保存删除的序号的表里取该用户的数据,如果没有,则用count()读取某用户所有的记录数+1。 
       保存操作:判断序列号用户有没有使用,如果使用了,则抛出序列号不唯一的错误。如果没有使用,则先从保存删除的序列号的表里删除该序列号,再保存数据。 
       现在的问题是:如果是几个人用,没有任何问题,但是100多人使用的时候,则有一小部分用户出现序列号不唯一的情况。我看了一下数据库,序列号不唯一的情况是没有从保存删除序列号的表里删除。 
      以下是业务层的代码: 
      Java代码 
/**  
*获取用户最大的序号  
*@param userId 用户Id  
*@return Integer 序号  
  */  
function Integer getNewSequence(long userId){   
    User user = new User(userId);   
    List<Sequence> sequences = this.getSequenceDao.findByUser(user);   
    if(sequences.size()>0){   
         return sequences.get(0).getSequence();   
    }   
    Integer sequence = this.getVoucherDao().getMaxSequence(user);   
    return sequence==null?1:(sequence+1);   
}   
  
/**  
保存操作,如果id为0,则添加,否则修改。  
*@param voucher   
*@exception SequenceNotUniqueException  
*/  
function void save(Voucher voucher) throws SequenceNotUniqueException{   
    if(voucher.isNew()){//问题产生的地方   
         boolean isExistsSuchSequence = this.getVoucherDao.isExistsSuchSequence(voucher.getUser(),voucher.getSequence());   
        if(isExistsSuchSequence){   
             throw new SequenceNotUniqueException("序列号不唯一,请重新输入序列号");   
        }   
        this.getSequenceDao().remove(voucher.getUser(),voucher.getSequence());   
        this.getVoucherDao().insert(voucher);   
    }else{   
         Voucher v = this.getVoucherDao().findBySequence(voucher.getUser(),voucher.getSequence());   
         if(v!=null && v.getId()!=voucher.getId()){   
              throw new SequenceNotUniqueException("该序列号已使用,请使用其他的序列号");   
         }   
         this.getVoucherDao().update(voucher);   
    }   
}   
/**  
删除操作  
*@param voucher  
*/  
public void remove(Voucher voucher){   
     Sequence sequence = new Sequence(voucher.getUser(),voucher.getSequence());   
     this.getSequenceDao().insert(sequence);   
     this.getVoucherDao().remove(voucher);   

解决方案 »

  1.   

    问题就出在那个保存删除序列号的表中,如果太多人操作。可能会发生脏数据。这就象在并发程序中,多个线程同时访问一个集合对象中的数据(对其进行增删操作)。如果这个集合对象不同步。就可能发生脏数据的情况。这个保存删除序列号的表也一样,假设有一个用户读了该表中的一条记录,当还未执行到删除该记录时,另一个用户也读了该记录。这就会造成两个用户拥有同一个序列号的情况,解决的方式是使用行锁,也就是说,当一个用户访问该表时,的某一条时,另一个用户不能再访问该行。也就是对表中的行进行同步。