일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- gitreset
- JPA
- HTTPMESSAGE
- HTTP3
- 네이버 연결된 서비스
- 자바ORM표준프로그래밍
- ERROR TYPE : org.apache.ibatis.binding.BindingException
- Transaction not successfully started
- 무상태프로토콜
- 네이버로그인API
- initialDelay
- gitrevert
- anyMatch
- 데이터베이스 방언
- SpringBoot
- KAKAOLOGINAPI
- 김영한JPA
- fixedDelay
- @Entity
- org.apache.ibatis.binding.BindingException
- 매핑정보가없는필드
- 멱등활용
- hibernate.dialect
- Invalid bound statement (not found)
- 캐쉬가능
- RFC723x
- Git
- http
- @Table
- DB방언
- Today
- Total
twocowsong
다 대 다 : 단방향 본문
다 대 다 단방향 관계인 회원 엔티티를 보겠습니다.
@Entity
public class Product {
@Id
@Column(name = "PRODUCT_ID")
private String id;
private String name;
}
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
private String username;
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();
// Getter, Setter...
}
회원 엔티티와 상품 엔티티를 @ManyToMany로 매핑하였습니다.
여기서 중요한 점은 @ManyToMany와 @JoinTable을 사용해서 연결 테이블을 바로 매핑한 것입니다.
따라서 회원과 상품을 연결하는 회원_상품(MEMBER_PRODUCT)엔티티 없이 매핑을 완료할 수 있습니다.
연결 테이블을 매핑하는 @JoinTable 속성을 정리해보겠습니다.
@JoinTable.name : 연결 테이블을 지정합니다. 여기서는 회원_상품 테이블을 선택하였습니다.
@JoinTable.joinColumns : 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정합니다.
@JoinTable.inverseJoinColumns : 반대 방향인 상품과 매핑할 조인 컬럼정보를 지정하였습니다.
MEMBER_PRODUCT 테이블은 다대다 관계를 일대다, 다대일 관계로 풀어내기 위해 필요한 연결 테이블일 뿐입니다.
@ManyToMany로 매핑한 덕분에 다대다 관계를 사용할 때는 이연결 테이블을 신경 쓰지 않아도 됩니다.
이제 다대다 관계를 저장하는 예제입니다.
public static void save(EntityManager em) {
Product productA = new Product();
productA.setId("productA");
productA.setName("상품 A");
em.persist(productA);
Member member1 = new Member();
member1.setId(1L);
member1.setUsername("회원1");
member1.getProducts().add(productA); // 연관관계 설정
em.persist(member1);
}
회원 1과 상품 A의 연관관계를 설정했으므로 회원1을 저장할 때 연결 테이블에도 값이 저장됩니다.
따라서 이 코드를 실행하면 다음과 같은 SQL이 실행됩니다.
MEMBER_PRODUCT도 INSERT되는것을 확일할수 있습니다.
INSERT INTO PRODUCT ..
INSERT INTO MEMBER ..
INSERT INTO MEMBER_PRODUCT ..
public static void find(EntityManager em) {
Member member = em.find(Member.class, "member1");
List<Product> products = member.getProducts(); // 객체 그래프 탐색
for (Product product : products) {
System.out.println("TestSave.find : " + product.getName());
}
}
저장한 후에 탐색해두었던 상품1이 조회됩니다.
member.getProducts()를 호출해서 상품이름을 출력하면 다음 SQL이 실행됩니다.
SELECT * FROM MEMBER_PRODUCT MP
INNER JOIN PRODUCT P ON MP.PRODUCT_ID = P.PRODUCT_ID
WHERE MP.MEMBER_ID = ?
실행된 SQL을 보면 연결 테이블인 MEMBER_PRODUCT와 상품 테이블을 조인해서 연관된 상품을 조회합니다.
@ManyToMany 덕분에 복잡한 다대다 관계를 애플리케이션에서는 아주 단순하게 사용할 수 있습니다.
위 예제를 저는 똑같이 따라해보았습니다.
4개의 테이블이 생성되었으며 현재 정상적으로 INSERT되지 않고있습니다. 에러는 아래와같습니다.
...
22:02:16.068 [main] DEBUG org.hibernate.service.internal.SessionFactoryServiceRegistryImpl - EventListenerRegistry access via ServiceRegistry is deprecated. Use `sessionFactory.getEventEngine().getListenerRegistry()` instead
22:02:16.076 [main] DEBUG org.hibernate.internal.SessionFactoryRegistry - Initializing SessionFactoryRegistry : org.hibernate.internal.SessionFactoryRegistry@78fe204a
22:02:16.078 [main] DEBUG org.hibernate.internal.SessionFactoryRegistry - Registering SessionFactory: b5ccdee9-d8ec-435c-aecb-17df6602dd78 (<unnamed>)
22:02:16.079 [main] DEBUG org.hibernate.internal.SessionFactoryRegistry - Not binding SessionFactory to JNDI, no JNDI name configured
22:02:16.142 [main] DEBUG org.hibernate.stat.internal.StatisticsInitiator - Statistics initialized [enabled=false]
22:02:16.147 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
22:02:16.147 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - begin
22:02:16.153 [main] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Generated identifier: productA, using strategy: org.hibernate.id.Assigned
22:02:16.168 [main] DEBUG org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl - JDBC transaction marked for rollback-only (exception provided for stack trace)
java.lang.Exception: exception just for purpose of providing stack trace
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.markRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:324)
at org.hibernate.engine.transaction.internal.TransactionImpl.markRollbackOnly(TransactionImpl.java:203)
at org.hibernate.internal.AbstractSharedSessionContract.markForRollbackOnly(AbstractSharedSessionContract.java:428)
at org.hibernate.internal.ExceptionConverterImpl.handlePersistenceException(ExceptionConverterImpl.java:297)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:762)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:742)
at com.jpa.study.entity.TestSave.save(TestSave.java:46)
at com.jpa.study.entity.TestSave.main(TestSave.java:23)
22:02:16.168 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - rolling back
22:02:16.169 [main] DEBUG org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - Initiating JDBC connection release from afterTransaction
22:02:16.170 [main] DEBUG org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - Initiating JDBC connection release from afterTransaction
아직 해결하지못한상황이며 추후 해결시에 본글을 수정해놓겠습니다.
'IT > JPA' 카테고리의 다른 글
다 대 다 : 매핑의 한계와 극복, 연결 엔티티 사용 (0) | 2022.06.26 |
---|---|
다 대 다 : 양방향 (0) | 2022.06.26 |
다 대 다 [N : N] (0) | 2022.06.20 |
대상 테이블에 외래 키 (0) | 2022.06.19 |
주 테이블 외래 키 (0) | 2022.06.19 |