[김영한 - 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 를 생성할 수 있다.

EntityMangerFactoryEntityManger를 생성한다

도메인 객체

@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





© 2020.12. by 따라쟁이

Powered by philz