
public class EntityManagerFactoryGenerator {
private static final EntityManagerFactory factory =
Persistence.createEntityManagerFactory("jpatest");
private EntityManagerFactoryGenerator() {}
public static EntityManagerFactory getInstance() { return factory; }
}
public class EntityManagerGenerator {
public static EntityManager getInstance() {
return EntityManagerFactoryGenerator.getInstance().createEntityManager();
}
}
테스트 포인트
@Entity(name = "Section02Menu")
@Table(name = "tbl_menu")
public class Menu {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "menu_code") private int menuCode;
@Column(name = "menu_name") private String menuName;
@Column(name = "menu_price") private int menuPrice;
@Column(name = "category_code") private int categoryCode;
@Column(name = "orderable_status") private String orderableStatus;
protected Menu() {}
public Menu(String menuName, int menuPrice, int categoryCode, String orderableStatus) { ... }
}
Unable to locate persister 발생 시persistence.xml 내 <persistence-unit>에 엔티티를 <class>로 명시<persistence-unit name="jpatest">
<class>com.ohgiraffers.section02.crud.Menu</class>
</persistence-unit>
(Spring Boot는 보통 스캔 문제 없음)
find(Entity.class, id) 기본키 조회getTransaction().begin() / commit() / rollback()persist(entity) 저장(커밋 시 INSERT)remove(entity) 삭제(커밋 시 DELETE)예시
// insert
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(newMenu);
tx.commit();
// update (영속 엔티티 변경감지)
tx.begin();
foundMenu.setMenuName("변경");
tx.commit();
// delete
tx.begin();
em.remove(foundMenu);
tx.commit();
EntityManager.contains()가 falsecontains()가 trueMenu managed = em.find(Menu.class, 1);
Menu transientMenu = new Menu(...);
assertTrue(em.contains(managed));
assertFalse(em.contains(transientMenu));
Menu a1 = em.find(Menu.class, 1);
Menu a2 = em.find(Menu.class, 1);
assertEquals(a1, a2); // 같은 EM
Menu b1 = lifeCycle.findMenuByMenuCode(1); // 내부적으로 다른 EM 사용
Menu b2 = lifeCycle.findMenuByMenuCode(1);
assertNotEquals(b1, b2);
detach(entity) 특정 엔티티만 준영속화 → 변경감지 비활성merge(detached) 준영속 객체 값을 영속 엔티티에 병합하여 반환핵심 시나리오 요약
tx.begin();
Menu m = em.find(Menu.class, id);
em.detach(m);
m.setMenuPrice(1000);
em.flush(); // 반영 안 됨
tx.rollback();
tx.begin();
Menu m2 = em.find(Menu.class, id);
em.detach(m2);
m2.setMenuPrice(1000);
em.merge(m2);
em.flush(); // 반영 됨
tx.rollback();
신규 저장 케이스(식별자 수동 세팅)
tx.begin();
detached.setMenuCode(999);
em.merge(detached); // 식별자 기준으로 없으면 insert
tx.commit();
clear() PC 초기화 → 모든 영속 엔티티가 준영속으로 전환close() PC 종료 → 이후 EM 사용 시 IllegalStateExceptionMenu m = em.find(Menu.class, 1);
em.clear();
Menu refetched = em.find(Menu.class, 1);
assertNotEquals(m, refetched);
em.close();
assertThrows(IllegalStateException.class, () -> em.find(Menu.class, 1));
remove() 호출 → 커밋/flush 시 DELETEtx.begin();
Menu m = em.find(Menu.class, 1);
em.remove(m);
em.flush();
assertNull(em.find(Menu.class, 1)); // 1차 캐시 관점
tx.rollback();
persistence.xml의 <class> 등록 문제 확인persistence.xml의 persistence-unit 이름과 코드 설정이 일치하는가persistence.xml에 <class> 추가, 패키지/경로 점검contains), 트랜잭션 경계 점검