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

时间:2016-09-04 11:36:25

标签: java spring oracle hibernate transactions

我的服务层中有一些业务检查,我在其中检查了一些查询和条件。

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

    }

1 个答案:

答案 0 :(得分:1)

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

这里的问题是,您希望保证没有其他交易会潜入,并添加具有相同过滤条件的Product

乐观锁定只有在数据库中已存在现有行时才能帮助您。因此,在您的情况下,乐观锁定仅适用于将行标记为已删除的情况。

但是,即使在查询执行时数据库中没有记录,您也希望此检查能够正常工作。在这种情况下,you need to use SERIALIZABLE因为它可以防止幻影读取和丢失更新。

您需要将当前事务注释为Serializable。查看this article for more info on this topic