[김영한 - JPA 기본] #2 시작
H2 DataBase
2MB 이하의 가벼운 용량
MySQL, Oracle 데이터베이스 시뮬레이션 기능
메이븐 pom 추가
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jpa-basic</groupId>
<artifactId>ex1-hello-jpa</artifactId>
<version>1.0.0</version>
<dependencies>
<!-- JPA 하이버네이트 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.3.10.Final</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
</dependency>
</dependencies>
</project>
persistence.xml 추가
- 위치:
프로젝트/resources/META-INF/
persistence.xml
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="hello">
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
javax.persistence로 시작: JPA 표준 속성
hibernate로 시작: 하이버네이트 전용 속성
Persistence
Persistence
객체가 persistence.xml
파일을 읽어들여서
EntityMangerFactory
를 생성할 수 있다.
EntityMangerFactory
는 EntityManger
를 생성한다
도메인 객체
@Entity
public class Member {
@Id
private Long id;
private String name;
}
@Entity
: JPA가 관리할 객체@Id
: 데이터베이스 PK와 매핑
사용 범위
EntityMangerFactory
는 하나만 생성해서 애플리케이션 전체에 서 공유EntityManger
는 쓰레드간에 공유X (사용하고 버려야 한다).
JPQL
- 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
- 아래 내용에 적어 놓았다
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존 X
만일 도메인 객체에 다른 Table명과 Column명을 사용하고 싶다면?
@Entity
@Table(name = "USER")
public class Member {
@Id
private Long id;
@Column(name = "user_name")
private String name;
...
위와 같은 어노테이션을 이용해서 수정할 수 있다
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
위는 JPQL이 테이블이 아닌 객체에 의존한다는 것을 보여주는 예제에디ㅏ Member
객체로 조회했지만 Table명이 User
에 매핑되어 있기 때문에 Member
객체를 조회한다
방언 설정
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
오라클, MySql 등의 설정이 가능하다
코드 작성
기본적인 코드는 아래와 같이 가져간다
Create
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// Create
Member member = new Member();
member.setId(1L);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
Read
Member member = em.find(Member.class, 2L);
System.out.println("member = " + member);
- 참고로 한 트랜젝션 내에서 두 객체를 꺼내 비교하면 (주소가 )같다 !
Member member = em.find(Member.class, 1L);
Member member2 = em.find(Member.class, 2L);
System.out.println("(member == member2) = " + (member == member2)); // true
Update
Member member = em.find(Member.class, 1L);
member.setName("MemberAA");
Delete
em.remove(member);
remove에 관해서..
아래 코드는 삭제가 되지 않는다
em.remove(new Member(1L, "swcho"));
Equals
를 오버라이드 해보았지만 여전히 삭제가 되지 않는다 !
find
로 가져온 객체 대해서만 지워지는 것으로 보인다
Read - 주소 비교시 일부로 다르게 나오도록 해보자
tx.begin();
member = em.find(Member.class, 1L);
tx.commit();
tx.begin();
member2 = em.find(Member.class, 1L);
System.out.println("(member == member2) = " + (member == member2));
tx.commit();
위와 같이 해도 결국 true 값이 나온다
똑같은 트랜잭션 객체를 사용해서 그런 것으로 보인다
해당 객체마저 바꾸어 보자
EntityTransaction tx2 = em.getTransaction();
tx2.begin();
member2 = em.find(Member.class, 1L);
System.out.println("(member == member2) = " + (member == member2));
tx2.commit();
2번째 트랜잭션 객체를 생성하더라도 결과는 동일하다 !
그렇다면 entityManger
까지 바꾸어 보자
EntityManager em2 = entityManagerFactory.createEntityManager();
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();
member2 = em2.find(Member.class, 1L);
System.out.println("(member == member2) = " + (member == member2));
tx2.commit();
위 실행결과는 false
이다
드디어 다른 것을 확인하였다
한 entityManger
에서 생성한 모든 transaction
은 모두 동일한 entity
를 가져온다
컬럼 글로벌 네이밍 전략
하이버네이트 버전 5 부터는 영한님 책에서 나온 설정이 레거시가 되어 더이상 동작하지 않는다.
따라서 아래의 설정으로 바꾸어주어야 한다고 한다.
<property name="hibernate.implicit_naming_strategy" value="org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl"/>
구체적으로 카멜케이스인 컬럼명을 언더스코어로 바꾸고자 한다면 직접 PhysicalNamingStrategy
라는 클래스를 구현해서 사용하면 된다
참고
컬럼 글로벌 네이밍 전략
https://velog.io/@mumuni/Hibernate5-Naming-Strategy-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC > https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#ImplicitNamingStrategy
https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#ImplicitNamingStrategy
gradle 에서는 순수 하이버네이트를 사용하려면
각 엔티티마다 아래의 설정이 필요하다
<class>hellojpa.domain.User</class>
참고 https://www.inflearn.com/questions/17098
그외 알게된 것
<property name="hibernate.hbm2ddl.auto" value="create" />
위 설정 항목이 있으면 해당 테이블이 있을시에 drop하고 다시 만들어준다
위처럼 설정이 되어있을 경우 나오는 메세지
Hibernate:
drop table Member if exists
Hibernate:
create table Member (
id bigint not null,
name varchar(255),
primary key (id)
)
헌치: 배포-과정-정리
https://velog.io/@betterfuture4/%EB%B0%B0%ED%8F%AC-%EA%B3%BC%EC%A0%95-%EC%A0%95%EB%A6%AC