2022. 3. 12. 21:26ㆍJPA
◎ JPA 프로젝트 생성
-> H2 데이터베이스를 사용한다.
-> 자바 라이브러리, 빌드 관리와 라이브러리 자동 다운로드 및 의존성 관리를 하는 메이븐을 사용한다.
-> persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
☞ JPA설정 파일이다.
☞ persistence-unit name으로 이름을 지정한다.
☞ javax.persistence로 시작하는 것은 JPA표준 속성이다.
☞ "javax.persistence.jdbc.driver" value = org.h2.Driver : 데이터베이스 접근 조건으로 h2 Driver사용함을 나타낸다.
◎ 데이터베이스 방언
-> SQL표준을 지키지 않는 특정 데이터베이스만의 고유한 기능을 방언이라고 표현한다. (ex 문자열을 자르는 함수를 SQL표준은 "SUBSTRING()", Oracle은 "SUBSTR()")
-> JPA는 특정 데이터베이스에 종속적이지 않다.
-> 각 데이터베이스가 제공하는 SQL문법과 함수는 다르다.
-> 방언 : SQL표준을 지키지 않는 특정 데이터베이스만의 고유한 특성이다.
-> hibernate.dialect 속성에 지정한다.
◎ EntityMangerFactory & EntityManager
-> EntityMangerFactory는 애플리케이션 로딩 시점에 딱 한 번만 만들어야 한다. 데이터베이스와 연결기능도 한다.
-> 실제 데이터베이스에 저장하거나 하는 트랜젝션 단위(고객이 어떤 요청을 하고 나감 등의 과정)마다 EntityManager를 만들어야한다.
◎ JPA 구동 방식
-> JPA의 Persistence라는 클래스에서 설정 정보 persistence.xml을 읽어서 EntityManagerFactory를 만들고 필요할 때 마다 EntityManager를 생성하여 실행한다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member);
tx.commit();
em.close();
emf.close();
}
}
☞ EntityTransaction tx = em.getTransaction();은 트랜젝션을 얻을 수 있다.
☞ tx.begin();은 트랜젝션을 시작한다.
-> Member
@Entity // 이게 있어여 JPA를 사용하는 것으로 인식을 한다.
public class Member {
@Id
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
☞ @Entity : JPA가 관리할 객체
☞ @Id : 데이터베이스 PK와 매핑
-> 결과
☞ 코드를 실행하면 위와 같이 쿼리가 출력된다.
☞ <property name="hibernate.show_sql" value="true"/>은 위와 같은 퀴리를 보여주게 한다.
☞ <property name="hibernate.format_sql" value="true"/>은 위 쿼리처럼 보기 편하게 정리를 한다.
☞ <property name="hibernate.use_sql_comments" value="true"/>은 쿼리가 왜 나왔는지 알려준다.
-> h2데이터베이스를 통해 데이터가 저장이 된 것을 확인할 수 있다.
☞ 위 코드는 문제가 발생하면 호출이 되지 않는 문제가 있다.
-> 다음과 같이 예외 처리를 하여 문제를 해결한다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Member member = new Member();
member.setId(1L);
member.setName("HelloJPA"); // 이렇게만 해도 수정 가능 em.persist필요 없다
em.persist(member);
tx.commit();
} catch(Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
-> 데이터 조회
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Member findMember = em.find(Member.class, 1L);
System.out.println("findMember.id = " + findMember.getId());
System.out.println("findMember.name = " + findMember.getName());
tx.commit();
} catch(Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
-> 결과
-> 삭제
☞ 삭제는 위 코드에서 em.remove()를 사용하면 된다.
-> 수정
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Member findMember = em.find(Member.class, 1L);
findMember.setName("HelloJPA");
tx.commit();
} catch(Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
-> 결과
-> h2 데이터 확인
☞ 결과를 통해 기존 HelloA에서 HelloJPA로 데이터가 변경된 것을 알 수 있다.
☞ em.persistence사용할 필요 없이 아래의 코드로 데이터를 수정할 수 있다.
Member findMember = em.find(Member.class, 1L);
findMember.setName("HelloJPA");
☞ JPA를 통해 엔티티를 가져오면 JPA가 관리를 한다. JPA가 변경 여부를 트랜젝션 커밋 시점에 체크를 해서 변경이 되었으면 커밋 직적에 업데이트 쿼리를 날리고 트랜젝션 커밋을 한다. 따라서 em.persistence로 저장할 필요없이 위 코드만으로 수정을 할 수 있다.
◎ 주의 사항
-> EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에 공유한다.
-> EntityManager는 고객의 요청이 올 때 마다 사용하고 버리고를 반복하기 때문에 스레드 간 공유는 할 수 없다.
-> JPA의 모든 변경은 트랜젝션 내부에서만 실행되어야 한다.
◎ JPQL
-> 가장 단순한 조회 방법이다.
-> 내가 원하는 데이터를 최적화해서 가져올 수 있다.
List<Member> result = em.createQuery("select m from Member as m", Member.class).getResultList();
☞ JPA는 객체를 대상으로 퀴리를 작성한다.
-> 예제
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
List<Member> result = em.createQuery("select m from Member as m", Member.class).getResultList();
for(Member member:result){
System.out.println("member.name = " + member.getName());
}
tx.commit();
} catch(Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
-> 결과
-> JPA를 사용하면 객체를 중심으로 개발한다. 하지만 데이터를 검색을 해야하는 경우 모든 데이터베이스를 객체로 변환해서 검색하는 것은 불가능하다. 애플리케이션에서 필요한 데이터만 불러오려면 검색 조건이 포함된 SQL이 필요하다. 그러나 이 방식은 데이터베이스에 종속적으로 설계를 해야 한다.
-> JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
-> SQL은 데이터베이스 테이블을 대상으로 쿼리를 한다.
-> JPQL은 엔티티를 객체를 대상으로 쿼리를 한다. 따라서 데이터베이스 방언을 바꿔도 코드를 변경할 필요가 없다는 장점이 있다.
★ 참고
자바 ORM 표준 JPA 프로그래밍 - 기본편