为什么hibernate自己执行更新?

时间:2016-11-17 18:49:46

标签: java spring hibernate

我刚接触休眠,但我不知道为什么会出现此错误。我注释掉了我的DAO代码进行更新,而hibernate仍在执行更新查询。这是我的服务代码。

@Override
@Transactional(readOnly = false)
public void updateProduct(Product productToUpdate) throws DuplicateProductException {

    Product product = productDao.findByProductId(productToUpdate.getProductId());

    if (productDao.findByName(productToUpdate.getName()) != null
            && !product.getName().equals(productToUpdate.getName())) {
        throw new DuplicateProductException();
    }

    product.setName(productToUpdate.getName());
    product.setCategory(productToUpdate.getCategory());
    product.setPrice(productToUpdate.getPrice());
    product.setImage(productToUpdate.getImage());

//      productDao.updateProduct(product);
   }

我评论了DAO,而hibernate仍在执行查询。

这是我的控制器的代码。

@RequestMapping(value = "/updateProduct", method = RequestMethod.POST)
public String updateProductPost(@Validated @ModelAttribute("product") ProductHelper productHelper,
        BindingResult bindingResult, Model model) throws CategoryNotFoundException {

    model.addAttribute("categories", categoryService.findAll());
    model.addAttribute("activePage", AdminPage.UPDATE_PRODUCT);

    updateProductValidator.validate(productHelper, bindingResult);

    if (bindingResult.hasErrors()) {
        return "admin_home";
    }

    Product product = productHelper.buildProductToUpdate(productService, categoryService);

    try {

        productService.updateProduct(product);
        model.addAttribute("updatedProduct", product);
    } catch (DuplicateProductException e) {

        model.addAttribute("duplicateProduct", product);
    }

    return "admin_home";
}

奇怪的是,我已将整个DAO代码注释掉了:

//  @Override
//  public void updateProduct(Product product) {
////        sessionFactory.getCurrentSession().update(product);
//  }

仍然是hibernate正在执行更新查询:

Hibernate: update PRODUCT set category_id=?, image=?, name=?, price=?, product_id=? where id=?
Hibernate: select product0_.id as id1_3_, product0_.category_id as category6_3_, product0_.image as image2_3_, product0_.name as name3_3_, product0_.price as price4_3_, product0_.product_id as product_5_3_ from PRODUCT product0_ where product0_.product_id=?
Hibernate: select product0_.id as id1_3_, product0_.category_id as category6_3_, product0_.image as image2_3_, product0_.name as name3_3_, product0_.price as price4_3_, product0_.product_id as product_5_3_ from PRODUCT product0_ where product0_.name=?

如果这是一些初学者的错误,我真的很抱歉,但我对hibernate相当新。谢谢。

1 个答案:

答案 0 :(得分:1)

JPA使用托管实体。这意味着,当会话关闭或刷新时,您对会话中的托管实体所做的任何更改都会保留。

解决方法您可以按copy constructor创建新实例:

Product productDetached = new Product(productDao.findByProductId(productToUpdate.getProductId()))
//you can change and do not worry about sql query
productDetached.setName(productToUpdate.getName());

如果您不想要这种行为,则需要手动分离实体。

如果您使用的是JPA 2.0,则可以使用EntityManager#detach()从持久性上下文中分离单个实体。此外,Hibernate还有一个Session#evict(),其用途相同:

由于JpaRepository本身不提供此功能,您可以添加custom implementation,如下所示:

public interface UserRepositoryCustom {

    ...
   void detachUser(User u);
    ...
}

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
    ...
}

@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
    ...
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void detachUser(User u) {
        entityManager.detach(u);
    }
    ...
}