spring data jpa:插入而不是删除

Posted

技术标签:

【中文标题】spring data jpa:插入而不是删除【英文标题】:spring data jpa: Insert instead of delete 【发布时间】:2018-11-25 05:49:04 【问题描述】:

我有一个基本的 SpringBoot 应用程序。使用 Spring Initializer、JPA、嵌入式 Tomcat、Thymeleaf 模板引擎,并将其打包为可执行 JAR 文件。我已经创建了这个 Repository 类:

@Repository
public interface MenuRepository extends CrudRepository<Menu, Long> 

      @Cacheable("menus")
      @Query("select cur from Menu cur where cur.MenuId = ?1")
      Menu findMenuByMenuId (String MenuId);

      @Cacheable("menus")
      @Query("select cur from Menu cur where lower (cur.symbol) = lower (?1) ")
      Menu findMenuBySymbol (String symbol);

还有这项服务:

@Service
public class MenuService 

        @Autowired
    protected MenuRepository menuRepository;    

    @Autowired
    MenuPriceService menuPriceService;


     @Transactional
     public Menu save (Menu menu)               
         return menuRepository.save (menu);
     


     @Transactional
     public void delete (Menu menu) 
         menuRepository.delete  (menu);
     
     ..




还有这个 JUNIT 测试:

    @Test
    @Transactional
    public void testDelete () 

        String menuName = System.currentTimeMillis()+"";

        Menu menu = new Menu(); 
        menu.setMenuId(menuName);
        menuService.delete (menu);

但这是我在控制台中看到的

Hibernate: 
    insert 
    into
        t_menu
        (...) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

【问题讨论】:

【参考方案1】:

虽然删除 @Transactional as suggested in another answer 可能会使行为消失,但我会质疑测试的有效性。

真正的问题是:为什么要尝试删除不在数据库中的实体?

解决办法:

如果你模拟不知道实体是否存在的情况,使用deleteById,当id不存在于数据库中时会抛出异常,你当然可以捕捉到。

有关此插入的方式和原因的一些背景知识:

delete(T entity) 是通过SimpleJpaRepository.delete(T entity) 实现的,基本上就是这一行代码。

em.remove(em.contains(entity) ? entity : em.merge(entity));

如您所见,如果实体不存在于EntityManager 中,它会对实体执行merge。如果没有merge,如果EntityManager 中确实存在另一个具有相同类和ID 的实例,那么会话中可能会出现重复的实体。但是由于您的实体根本不存在,这会触发插入数据库。

你可能会这样想:你创建一个实例,你让EntityManager知道它(通过告诉它删除它)然后你删除它,所以这些是需要在数据库中发生的步骤 - > 插入 + 删除。

【讨论】:

【参考方案2】:

删除@Transactional:

@Test
    public void testDelete () 

        String menuName = System.currentTimeMillis()+"";

        Menu menu = new Menu(); 
        menu.setMenuId(menuName);
        menuService.delete (menu);

【讨论】:

以上是关于spring data jpa:插入而不是删除的主要内容,如果未能解决你的问题,请参考以下文章

spring data jpa使用spring data jpa时,关于service层一个方法中进行删除和插入两种操作在同一个事务内处理

spring data jpa 能不能只返回一个字段的值,而不是整个对象

Spring Data JPA : 批量增删

Spring Data JPA : 批量增删

Spring Data JPA : 批量增删

Spring data JPA:如何启用级联删除而不引用父级中的子级?