我的服务层中有一些业务检查,我在其中检查了一些查询和条件。
他们不能在数据库层中作为唯一或检查。但在并发中,两个请求通过检查并在我的数据中出错。 问题是:我从用户控件中获取商品序列号,并且如果数据库中不存在,则我检查商品序列与数据库是否允许它保存记录,否则抛出异常。 图像有助于更好地理解问题: http://pasteboard.co/gPE0BRlRK.jpg
我们可以在hibernate上使用悲观锁,但是如果我们在数据库中没有任何记录,编号为A100,例如检查传递和数据库中的两个事务提交。
保存方法在这里:
@Override
public Long save(Product entity) {
if (!isUniqueForSave(entity))
throw new ApplicationException(saveUniqueError);
return super.save(entity);
}
,方法是UniqueForSave:
private boolean isUniqueForSave(Product entity) {
return iProductRepository.isUniqueForSave(entity);
}
,DAO层中的查询在此方法中:
public boolean isUniqueForSave(Product entity) {
Session session = getSession();
String hql = "select c from " + domainClass.getName() + " c "
+ " where c.ProductNumber = :productNumber "
+ " and c.item.id = :itemId "
+ " and c.deleted = 0 ";
if (entity.getId() != null && entity.getId() > 0)
hql += " and c.id != "+entity.getId();
Query query = session.createQuery(hql);
query.setParameter("productNumber ", entity.getProductNumber());
query.setParameter("itemId ", entity.getItem().getId());
List<Product> productsList = query.list();
if(productsList .size() > 1)
return false;
else if(productsList .size() == 0)
return true;
Product product= productsList .get(0);
if(entity.getOldItem() != null && product.getId().equals(entity.getOldItem().getId()))
return true;
return false;
}
答案 0 :(得分:1)
您的代码容易受到SQL注入攻击。你真的想要修复它!
这里的问题是,您希望保证没有其他交易会潜入,并添加具有相同过滤条件的Product
。
乐观锁定只有在数据库中已存在现有行时才能帮助您。因此,在您的情况下,乐观锁定仅适用于将行标记为已删除的情况。
但是,即使在查询执行时数据库中没有记录,您也希望此检查能够正常工作。在这种情况下,you need to use SERIALIZABLE
因为它可以防止幻影读取和丢失更新。
您需要将当前事务注释为Serializable。查看this article for more info on this topic。