JPA更新查询不支持DML操作

63

这个问题以前已经被问过一次,但解决方案并没有解决这个问题。我正在创建一个JUnit测试:

 @Test
    @Transactional
    @Modifying
    public void updateMaterialInventory() throws Exception{

        // Initialize the database
        materialRepository.saveAndFlush(material);

        long id =  material.getId();
        materialRepository.updateMaterialInventory(id,UPDATED_INVENTORY_COUNT);

        assertEquals(material.getInventory_count(), UPDATED_INVENTORY_COUNT, 0);
    }

上面的测试所调用的查询是:

 @Query("UPDATE Material m SET m.inventory_count = ?2 WHERE m.id = ?1")
    void updateMaterialInventory(Long id,int newInventoryAmount);

错误:
Caused by: org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations [UPDATE com.htd.domain.Material m SET m.inventory_count = ?2 WHERE m.id = ?1]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.errorIfDML(QueryTranslatorImpl.java:318)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:369)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:231)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
    at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:495)
    ... 55 more
4个回答

128
@Modifying注解必须放在updateMaterialInventory方法上,与@Query注解一起使用,让Spring-data知道这个查询语句不是用于选择值,而是用于更新值。

2
为什么我在更新时会收到“执行更新/删除查询”异常? - Mahdi
2
@Kenji 请添加以下内容: @Transactional(propagation = Propagation.REQUIRED, readOnly = false) - user64141
在调用存储库的服务中添加@Transactional。在存储库的查询方法中添加@Modifying - Antoine Dahan

4
据我所知,你不应该在仓库类中使用@Transactional注解。请查看以下答案。

服务实现类

import org.springframework.transaction.annotation.Transactional;
...
@Test
@Transactional
public void updateMaterialInventory() throws Exception{

    // Initialize the database
    materialRepository.saveAndFlush(material);

    long id =  material.getId();
    materialRepository.updateMaterialInventory(id,UPDATED_INVENTORY_COUNT);

    assertEquals(material.getInventory_count(), UPDATED_INVENTORY_COUNT, 0);
}

仓库类

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
...

  @Modifying
  @Query("UPDATE Material m SET m.inventory_count = ?2 WHERE m.id = ?1")
  void updateMaterialInventory(Long id,int newInventoryAmount);

请确保使用正确的导入。希望这能有所帮助。

3
@Transactional
@Modifying
@Query(DELETE_INVOICE_BY_NUMBER)
public void deleteInvoiceByNumber(@Param("number") int number);

这对我很有帮助,但是如果仓库类中没有@ Transactional,它就会报错。

这个方法起作用了,但是为什么@Transactional必须放在repository里面呢?如果我把它放在调用的方法外面,还是会出错... - SDekov

2

当您添加了@Modifying但仍然无法正常工作时,请确保您的查询类型为void,因此不返回任何内容。

Hibernate在其内部尝试获取日期,这导致了异常(而不是更新语句本身)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接