mybatis 보다는 jpa를 사용하는게 장래성이 더 있을 것 같아서 jpa 공부를 시작.
참고: jpa 프로그래밍 (김영한 저)
객체와 관계형 DB가 지향하는 목적(?)이 다른 것을 객체와 관계형 DB의 패러다임 불일치 문제라고 합니다.
객체는 참조로 다른 객체와 연관을 짓지만
테이블은 외래키를 이용해서 다른 테이블과 조인하여 연관을 짓는데
이 두 방법이 아주 상반된 방법이라서 양립하기 힘들다고 합니다.
Java Persistent API의 줄임말이며 자바 ORM 기술 표준 명세(인터페이스)입니다. 이 인터페이스를 구현한 것이 여럿 있고, 하이버네이트가 대표적이라 합니다.
ORM은 Object-Relational Mapping으로 객체와 관계DB(테이블)을 매핑한다는 것입니다. Mybatis가 SQL 매퍼로 객체와 SQL을 매핑한 것과 조금 달리 객체와 테이블을 매핑합니다.
자바 어플리케이션 <-> JPA <-> JDBC API <-> DB 와 같은 구조로 상호작용합니다.
JPA도 DB처리를 쉽게 해주는 JDBC 인터페이스의 일종입니다.
JPA를 사용하는 이유는 JPA가 패러다임 불일치를 해결하고,적절한 SQL을 알아서 생성해준다고 하네요. 그러면서 인터페이스이므로 다른 DB로의 교체가 쉽고,객체지향적인 관점도 잃지 않을 수도 있다고 하는데.. 좀 더 사용해봐야 알거 같네요.
h2 1.4.200을 다운받으면 오류가 있습니다. 1.4.199로 다운받아야 합니다.
윈도우의 경우 설치 후 C:\Program Files (x86)\H2\bin로 가서 h2 배치 파일 실행합니다.
그러면 로컬호스트로 h2 console에 접근가능합니다.
접속해서 테이블을 만들어주면 왼쪽편에 테이블이 만들어진 모습을 볼 수 있습니다.
<!-- JPA, 하이버네이트 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2db.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
src/main/resources/META-INF/persistence.xml에 JPA 관련 설정을 해야합니다.
이 경로에 persistence.xml이라는 이름의 파일을 만들어 놓으면 JPA가 인식할 수 있다고 합니다.
여기서 persistence-unit을 설정하고 JPA,하이버네이트,DB dialect를 설정합니다.
dialect는 한글로 방언,파생된 것이라는 의미입니다.
JPA가 인터페이스이기 때문에 이를 구현한 것을 지정해주는 것입니다.
이제 H2 database를 켜고 JPA를 테스트해 볼 수 있습니다.
비즈니스 요구사항을 모델링한 객체를 Entity라고 합니다.
롬복의 @Getter,@Setter를 이용해서 setter,getter를 자동으로 만들어주도록 했습니다.
@Entity를 붙이면 DB 테이블과 매핑될 클래스라는 것을 명시합니다.
@Table(DB 테이블명)으로 이 클래스가 어떤 테이블과 연관되는지 알려줍니다.
@Id : primary key로 사용될 속성이라고 명시합니다.
@Column(DB 컬럼명)을 붙여서 객체의 이 속성이 DB의 어떤 컬럼과 매핑될지 정합니다.
@Column을 붙이지 않으면 기본적으로 객체의 필드명과 DB의 컬럼명이 같은 것을 매핑합니다.
@Getter
@Setter
@Entity
@Table(name="MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String username;
private Integer age;
}
public class JpaMain {
public static void main(String[] args) {
//엔티티 매니저 팩토리 생성
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpabook");
EntityManager manager = factory.createEntityManager(); //엔티티 매니저 생성
EntityTransaction transaction = manager.getTransaction(); //트랜잭션 기능 획득
try {
transaction.begin(); //트랜잭션 시작
businessLogic(manager); //비즈니스 로직
transaction.commit();//트랜잭션 커밋
} catch (Exception e) {
e.printStackTrace();
transaction.rollback(); //트랜잭션 롤백
} finally {
manager.close(); //엔티티 매니저 종료
}
factory.close(); //엔티티 매니저 팩토리 종료
}
public static void businessLogic(...){...}
}
EntityManagerFactory 클래스 : 엔티티를 관리하는 매니저를 만드는 공장입니다. 이 공장은 Persistence 클래스를 통해 만드네요.
추가로 이 공장을 만드는 데 비용이 많이 듭니다. 따라서 이 공장은 어플리케이션에서 1개만 만들어 두고 재사용하는 방식으로 이용해야 합니다.
(스프링에서 쓰일 때는 빈으로 등록...?)
EntityManager 클래스 : Entity를 관리하는 매니저입니다. 이 EntityManager를 이용해서 CRUD를 할 수 있습니다. 행동대장같은 역할입니다.
EntityTransaction : JPA는 항상 트랜잭션 안에서 데이터를 변경해야 한다고 하네요. 예외를 반환할 수 있기 때문에 try-catch로 감싼 모습입니다.
<businessLogic메서드>
public static void businessLogic(EntityManager manager) {
String id = "id1";
Member member = new Member();
member.setId(id);
member.setUsername("g00dluckroon");
member.setAge(27);
//등록
manager.persist(member);
//수정
member.setAge(20);
//한 건 조회
Member findMember = manager.find(Member.class, id);
System.out.println("findMember=" + findMember.getUsername() + ", age=" + findMember.getAge());
//목록 조회
List<Member> members = manager.createQuery("select m from Member m", Member.class).getResultList();
System.out.println("members.size=" + members.size());
//삭제
manager.remove(member);
}
javax.persistence.EntityManager 클래스의 메서드들.
public abstract void persist(Object o)
등록할 때 사용합니다. persist에 객체를 넘겨주면 매니저가 SQL을 만들어서 DB에 전달해줍니다.
public abstract T find(Class aClass, Object o)
클래스와 @Id가 붙은 필드를 넘겨주면 조회를 할 수 있게 해줍니다.
public abstract void remove(Object o)
삭제할 엔티티를 넘겨주면 또한 매니저가 삭제해줍니다.
public abstract javax.persistence.TypedQuery
createQuery(String s, Class aClass)
이 또한 테이블이 아닌 엔티티 객체를 대상으로 이루어집니다.
위 코드에서 보면 SQL문이 일반적인 것과 조금 다른걸 볼 수 있는데 이게 SQL이 아니라 JPQL(Java Persistence Query Language)라고 합니다. 문법은 거의 비슷한데 SQL은 DB 테이블을 대상으로 하는 반면,
JPQL은 엔티티 객체 를 대상으로 합니다!!!!!!
그래서 위 코드에서 createQuery 내에 있는 JPQL에서 Member은 테이블명이 아니라 클래스명입니다!!!!!!!!!!!
객체 수정시 매니저를 호출해서 따로 해줄 필요가 없다고 합니다. 놀랍게도 JPA는 엔티티의 변경을 추적한다고 하네요...