如何保证事务服务方法中的行级唯一约束?

How to guarantee a row-level unique constraint in a transactional service method?

我在我的服务层进行了一些业务检查,在那里我用一些查询和条件检查它。

他们不能在数据库层做唯一性或检查。但是并发两个请求通过检查并在我的数据中出错。 问题是:我从用户控件中获取商品序列号,如果数据库中不存在商品序列号,我会用数据库检查商品序列号,让它保存记录,否则会抛出异常。 该图像有助于更好地理解问题: 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;

    }

您的代码容易受到 SQL 注入攻击。你真的也想修好它!

这里的问题是你要保证没有其他事务会偷偷溜进来,加一个Product同样的过滤条件

只有在数据库中已有行的情况下,乐观锁定才能为您提供帮助。因此,在您的情况下,乐观锁定仅在行被标记为已删除时才起作用。

但是,即使在执行查询时数据库中没有记录,您也希望此检查有效。在这种情况下,您需要使用 SERIALIZABLE,因为它可以防止幻读和丢失更新。

因此,您需要将当前交易注释为SERIALIZABLE