spring 数据 jpa:插入而不是删除
spring data jpa: Insert instead of delete
我有一个基本的 Spring 启动应用程序。使用 Spring 初始化程序、JPA、嵌入式 Tomcat、Thymeleaf 模板引擎,并将其打包为可执行 JAR 文件。我已经创建了这个存储库 class:
@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
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
移除 @Transactional
:
@Test
public void testDelete () {
String menuName = System.currentTimeMillis()+"";
Menu menu = new Menu();
menu.setMenuId(menuName);
menuService.delete (menu);
}
虽然删除 @Transactional
可能会使该行为消失,但我会质疑测试的有效性。
真正的问题是:为什么要尝试删除不在数据库中的实体?
解决方案:
如果你模拟不知道实体是否存在的情况,使用deleteById
它会在数据库中不存在id时抛出异常,你当然可以捕获它。
此插入发生的方式和原因的一些背景信息:
delete(T entity)
是通过 SimpleJpaRepository.delete(T entity)
实现的,它基本上包含这一行代码。
em.remove(em.contains(entity) ? entity : em.merge(entity));
如您所见,如果 EntityManager
中不存在实体,它会对实体执行 merge
。如果没有 merge
,如果 EntityManager
中确实存在另一个具有相同 class 和 Id 的实例,您最终可能会在会话中得到重复的实体。但是由于您的实体根本不存在,这会触发插入到数据库中。
您可能会这样想:您创建一个实例,让 EntityManager
知道它(通过告诉它删除它)然后删除它,所以这些是需要发生的步骤在数据库中 -> 插入 + 删除。
我有一个基本的 Spring 启动应用程序。使用 Spring 初始化程序、JPA、嵌入式 Tomcat、Thymeleaf 模板引擎,并将其打包为可执行 JAR 文件。我已经创建了这个存储库 class:
@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
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
移除 @Transactional
:
@Test
public void testDelete () {
String menuName = System.currentTimeMillis()+"";
Menu menu = new Menu();
menu.setMenuId(menuName);
menuService.delete (menu);
}
虽然删除 @Transactional
真正的问题是:为什么要尝试删除不在数据库中的实体?
解决方案:
如果你模拟不知道实体是否存在的情况,使用deleteById
它会在数据库中不存在id时抛出异常,你当然可以捕获它。
此插入发生的方式和原因的一些背景信息:
delete(T entity)
是通过 SimpleJpaRepository.delete(T entity)
实现的,它基本上包含这一行代码。
em.remove(em.contains(entity) ? entity : em.merge(entity));
如您所见,如果 EntityManager
中不存在实体,它会对实体执行 merge
。如果没有 merge
,如果 EntityManager
中确实存在另一个具有相同 class 和 Id 的实例,您最终可能会在会话中得到重复的实体。但是由于您的实体根本不存在,这会触发插入到数据库中。
您可能会这样想:您创建一个实例,让 EntityManager
知道它(通过告诉它删除它)然后删除它,所以这些是需要发生的步骤在数据库中 -> 插入 + 删除。