시뻘건 개발 도전기

JPA를 사용하기 위한 설정과 동작 원리 본문

API/JPA

JPA를 사용하기 위한 설정과 동작 원리

개발자 시뻘건볼때기 2020. 9. 29. 22:00

  JPA를 사용하는 궁극적인 목적은 데이터베이스 관점의 테이블과 객체지향적 객체 사이에서 개발자가 해야할 일을 최소화하고 객체지향적으로 자유롭게 개발하기 위해서다. 따라서, JPA를 사용하려면 가장 먼저 객체를 매핑해야한다.

 

- 객체 매핑

CREATE TABLE MEMBER (
	ID VARCHAR(255) NOT NULL,
	NAME VARCHAR(255),
	AGE INTEGER,
	PRIMARY KEY (ID)
)

위 테이블은 아래와 같이 객체 매핑을 할 수 있다.

@getter
@setter
@Entity
@Table(name="MEMBER")
public class Member {
	@id
	private String id;
    
	@Column(nullable = true, length = 255, unique = false)
	private String username;
    
	private String age;
}

- @getter와 @setter 어노테이션은 lombok을 이용한 것이다. 해당 내용을 알고 싶다면 #18 : Lombok을 참고하자.

- @Entity 어노테이션은 해당 클래스가 엔티티라고 정의하는 역할을 한다. 엔티티라는 이야기는 곧 데이터베이스 테이블과 매핑이 되는 클래스를 이야기 한다.

- @Table 어노테이션으로 name Element를 전달함으로써 해당 클래스가 매핑될 테이블 명을 정의한다. 만약, 정의하지 않는다면 class명으로 table을 찾고 없으면 table create문을 날리기도 한다.(이 부분은 설정에 따라 안하게 할 수도 있다.)

- @id 어노테이션은 해당 컬럼이 기본키(primary key)라고 정의한 것이다.

- @Column 어노테이션으로 세 가지의 Element를 주었다.

  • nullable : NULL값 허용인지?
  • length : max length
  • unique : unique key 정의
  • (그 외의 Element는 아래 내용 참고)

그 외에도 많은 어노테이션과 Element들이 있다. 이 것들을 전부 외울 수 없으니 이 docs를 옆에 끼고 개발하자. 해당 docs는 java 7버전이며, 본인이 개발 환경에 맞는 docs를 보는 것을 권장한다.

 

  위에서 살펴본 어노테이션은 javax.persistence.* package에 포함되어있다. JPA는 persistence.xml을 사용해서 설정 정보를 관리한다. spring MVC와 spring Boot간 차이가 있을 수 있으니 함께 알아보자.

 

- Spring Boot

  application.properties 파일에 다음과 같이 설정한다.

spring.datasource.url=jdbc:mysql://127.0.0.1:9999/TEST?serverTimezone=UTC
spring.datasource.username=dotori
spring.datasource.password=dotori
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
  • spring.jpa.hibernate.dll-auto : create, create-drop, update, validate, none을 정의할 수 있다.
    • create : 테이블이 없을 때 자동 생성한다.
    • create-drop : JPA 종료 시점에 기존에 있었던 테이블을 삭제한다.
    • update : JPA에 의해 변경된 부분만 update.
    • validate : 테이블과 객체가 잘 매핑되어 있는지 체크한다.
    • none : 초기화 동작을 하지 않는다.
  • spring.jpa.generate-dll : spring.jpa.hibernate.dll-auto옵션을 사용할 것인가? default가 false. JPA에 의한 데이터베이스 자동 초기화 기능을 사용하려면 true로 설정한다.
  • spring.jpa.show-sql : JPA가 생성한 SQL문을 보여준다. (로깅인지 System out인지는 모르겠음)

 

- Spring MVC

  #17 : H2 database 연동 준비를 참고하자.

 

 

 

  본 게시글을 보면 알 수 있듯이 mysql과 H2 database를 사용하였다. JPA란?에서 언급했듯이 JPA는 특정한 데이터베이스에 종속되어 있는 기술이 아니기 때문에 쉽게 바꿀 수 있다. 그러나 데이터베이스 간에 다음과 같은 차이점을 가지고 있다. (그 외에도 차이점은 많을 것으로 보인다.)

- 데이터 타입 : 가변 문자 타입으로 mysql은 varchar, Oracle은 varchar2를 사용한다.

- 다른 함수명 : 문자열을 자르는 함수로 SQL 표준은 substring(), Oracle은 substr()을 사용한다.

- 페이징 처리 : mysql은 limit, Oracle은 rownum을 사용한다.

이 처럼 특정 데이터베이스만의 고유한 기능을 JPA에서 방언(Dialect)라 한다. 하이버네이트는 다양한 데이터베이스 방언을 제공한다. (이외에도 많은 방언 제공함)

- H2 : org.hibernate.dialect.H2Dialect

- Oracle 10g : org.hibernate.dialect.Oracle10gDialect

- mysql : org.hibernate.dialect.MySql5InnoDBDialect

우리는 애플리케이션 코드를 변경할 필요 없이 하이버네이트의 방언만 교체해주기만 하면 된다.

예를 들어 설정 정보를 보자.

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="packagesToScan"
			value="com.maenginyoung.kakaopaycardtask.model" />
		<property name="dataSource" ref="dataSource" />

		<property name="jpaProperties">
			<props>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">create</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.use_sql_comments">true</prop>
				<prop key="hibernate.id.new_generator_mappings">true</prop>
			</props>
		</property>

		<property name="persistenceProvider">
			<bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
		</property>

	</bean>

 

 

  본격적으로 애플리케이션을 개발해보자. 다음 코드와 같이 JPA를 활용할 수 있다.

여기서 jpabook은 springMVC에서 persistence.xml에서 부여한 영속성 유닛(엔티티를 영구적으로 저장하는 환경) 이름을 이야기한다.

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        try {
            tx.begin();
            logic(em);
            tx.commit();
        } catch(Exception ex) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
 
    public static void logic(EmtityManager em) {
        String id = "dotori";
        Member member = new Member();
        member.setMemberId(id);
        member.setMemberName("도토리");
        member.setAge(28);
        
        // 등록
        em.persist(member);
        // INSERT INTO MEMBER (ID, NAME, AGE) VALUES ('DOTORI', '도토리', 28)
        
        // 수정
        member.setAge(19);
        // UPDATE MEMBER SET AGE=19 WHERE ID='dotori'
        
        // 한 건 조회
        Member findMember = em.find(Member.class, id);
        System.out.println("findMember=" + findMember.getMemberName() + ", age=" + findMember.getAge());
        // SELECT * FROM MEMBER WHERE ID='dotori'
        
        // 목록조회
        List<member> members = em.createQuery("select m from Member m", Member.class).getResultList();
        System.out.println("member size=" + members.size());
        // SELECT M.ID, M.NAME, M.AGE FROM MEMVER M

        // 삭제
        em.remove(member);
        // DELETE FROM MEMBER WHERE ID='dotori'
    }
}

크게 3부분으로 엔티티 매니저 설정 -> 트랜잭션 관리 -> 비즈니스 로직 실행 순으로 이루어져있다.

  • 엔티티 매니저 설정
    • 앤티티 매니저 팩토리 
      • 데이터베이스 커넥션 풀 생성하는 매개체
      • 생성 비용이 크다.
      • 애플리케이션 전체에서 오직 한 번만 생성하여 공유 사용 권장
    • JPA의 기능 대부분을 제공한다. (이를테면 CRUD)
    • 데이터베이스와 통신하는 매개체
    • 스레드간에 공유하거나 재사용 금지.
  • 트랜잭션 관리
    • 데이터 변경이 이루어지는 공간.
    • 예외가 발생하면 롤백 실행
  • 비즈니스 로직
    • 수행해야 하는 로직을 수행.
    • 엔티티 매니저를 사용하여 데이터베이스에 CRUD 수행.

 

  목록조회 코드를 잘 보면 sql query가 들어가 있는 것을 알 수 있다. 우리는 엔티티 객체를 중심으로 개발(객체지향적으로)하고 데이터베이스에 대한 처리는 JPA에게 맡겨야 한다. 만약 테이블이 아닌 엔티티 객체를 대상으로 검색을 하게 된다면 모든 데이터를 애플리케이션으로 불러와서 엔티티 객체로 변경한 다음 그 객체에서 검색해야할 것이다. 사실상 붕가능에 가깝다고 보여진다.

  JPA는 JPQL(Java Persistence Query Language)를 지원 함으로써 검색 조건이 포함된 SQL을 사용할 수 있다. JPQL은 SQL을 추상화한 객체지향 쿼리 언어라고 정의된다. SQL과 거의 유사하지만 다음과 같은 차이점을 보인다.

- JPQL은 엔티티 객체를 대상으뤄 query를 날린다. (클래스와 필드를 대상으로)

- SQL은 데이터베이스 테이블을 대상으로 query를 날린다.

  상위 코드에서 보여진 select m from Member mㅇ; 비러 JPQL이다. 당연히 이 JPQL문의 Member는 Class Member를 이야기한다.

'API > JPA' 카테고리의 다른 글

Entity와 영속성 #2  (0) 2020.11.29
Entity와 영속성 #1  (0) 2020.11.29
JPA를 사용하기 위한 설정과 동작 원리  (0) 2020.09.29
JPA란?  (0) 2020.09.24
DB 연동 시 유의할 점 #2  (0) 2020.09.18
DB 연동 시 유의할 점 #1  (0) 2020.09.18
0 Comments
댓글쓰기 폼