주니 개발 도서관

JPA

[ JPA ] JPA 기초

주니홍 2022. 11. 1. 14:41

[ JPA ]

JPA설명, 생성, 설정, 기초 사용방법 정도를 작성해 보았습니다!

 

 

JPA 설명

 

JPA를 쉽게 얘기하자면
자바 객체와 DB테이블을 자동 매핑해주고
SQL문이 아닌 Method를 통해 DB를 조작할 수 있게 됩니다!

 

장점

1. SQL문이 아닌 Method를 통해 DB조작 = 비즈니스 로직을 구성하는데만 집중 가능

 

2. 쿼리와 같이 필요한 선언문, 할당 등의 부수적인 코드가 줄어들고

각종 객체에 대한 코드를 별도로 작성하여 코드의 가독성이 높아짐

 

3. 객체 지향적인 코드 작성이 가능. 객체지향적 접근만 고려하면 되기때문에 생산성 증가

 

4. DBMS 변경시 ex) MySQL >> Oracle, 새로 쿼리를 짜야하는 경우가 생기는데

이런경우 ORM ( JPA ) 를 사용한다면 쿼리를 수정할 필요가 없음

 

5. 매핑하는 정보가 Class로 명시 되었기 때문에 ERD를 보는 의존도를 낮출 수 있고

유지보수 및 리팩토링**에 유리

 

리팩토링(refactoring)은 소프트웨어 공학에서 '결과의 변경 없이 코드의 구조를 재조정함'을 뜻한다.

1) 가독성과 유지보수성을 높임

= 기능은 유지하되 읽기 좋고 지속적으로 관리하기 편하게 소스코드를 재작성함

 

2) 협업

= 소스코드를 작성할대 여러명의 사람과 함께 작업을 하게 된다

새로운 사람이 내가 작성하는 프로젝트에 추가로 참여하게되며

인수인계가 되거나 불가능한 경우도 있다

같이 협업을 하는 사람이 이해할수 있는 코드를 작성하는 것이 중요하다

 

리팩토링하는 이유

- 소프트웨어 설계에 질적 향상을 위해 리펙토링을 한다

- 코드중복제거, 수정 용이성 향상, 이해도의 복잡도를 낮춤, 가독성을 향상시키기 위해 한다

- 버그를 찾는데 도움이 된다

- 프로그램 개발 속도가 향상된다

 

 

단점

1. 프로젝트의 규모가 크고 복잡하여 설계가 잘못된 경우

속도 저하 및 일관성을 무너뜨리는 문제점이 생길 수 있음

 

2. 복잡하고 무거운 쿼리는 속도를 위해 별도의 튜닝이 필요하기 때문에

결국 SQL문으로 작성해야 할 수 있음

 

3. 학습 비용이 비쌈

 

 

 

그렇다면 왜 JPA를 사용해야 할까?

JPA는 반복적인 CRUD SQL을 처리해 준다

JPA는 매핑된 간계를 이용해서 SQL을 생성하고 실행하는데

개발자는 어떤 SQL이 실행될지 생각만하면 되고, 예측도 쉽게 할 수 있다

 

JPA를 사용하여 얻을 수 있는 가장 큰 것은 SQL아닌 객체 중심으로 개발할 수 있다는 것이다.

이에 따라 당연히 생산성이 좋아지고 유지보수도 수월하다.

( 더 이유가 존재하지만 기초니까 여기까지.. )

 


 

생성 및 설정

 

** 이클립스, Java 11 , Oracle DB, Spring 을 이용했습니다

 

 

( pom.xml )

JPA를 사용하기위해 dependency를 작성합니다 

 

 

 

( 프로젝트 Properties )

프로젝트 설정에서 JPA를 체크해주고 버전을 확인해 줍니다

실습은 2.1버전으로 준비했습니다.

 

( 2.1 >> 2.2 업그레이드 되면서 바뀐부분이 많이 생겼다 하여 추가 공부해야할 것 같습니다 )

 

 

 

JPA Entity 클래스를 생성합니다

이는 VO의 역할을 해줄 것입니다 ( 자동 매핑을 위해 )

 

 

jpa 패키지를 생성하여 JPA Entity 클래스를 생성하였습니다

Class name은 테이블명과 동일하게 작성해주는 것이 좋습니다

 

+ 추가적으로 Main메소드를 사용할 JAPClient 클래스를 생성하였습니다

 

Entity 클래스를 생성하게되면
META-INF 폴더가 생기고 - JPA 설정파일이 생긴다

 

 

( JPA 설정파일 - persistence.xml )

5가지 설정은 필수설정 **

driver, url, user, password는 항상 입력했던 것이기에 설명은 생략

 

dialect 설정

SQL 표준문법을 DBMS(방언)에 맞춰 만들어줌 >> 설정한 DBMS에 맞춰서 SQL문을 생성해준다
DBMS마다 설정이 다르고 버전마다도 다르기 때문에 확인해야한다!

 

 

선택옵션 (작성 안해도 상관 없음 )

<property name="hibernate.show_sql" value="true" />

콘솔에 하이버네이트가 실행하는 SQL문을 출력


<property name="hibernate.format_sql" value="true" />

SQL 출력시 보기 쉽게 정렬


<property name="hibernate.use_sql_comments" value="true" />

쿼리 출력시 주석 ( comments )도 함께 출력

 

 

 

 

 

Entity 생성하여 열어보면 해당 부분은 사용하지 않기때문에 지워주었습니다

 

 

( Board Entity )

완성된 Board 관련 Entity 입니다

 

@Entity

@Table

@SequenceGenerator

@Id

@GeneratedValue

 

중요해보이는 어노테이션이 보입니다.

 

그 이외에는 VO 작성과 동일하게 DB테이블 칼럼과 매핑할 수 있도록

데이터타입과 변수명을 설정해 줍니다 ( + getter & setter 설정 )

 

 

@관련 설명

 

@Entity

해당 클래스는 Entity 클래스라는 것을 알려주는 어노테이션

 

@Table

Entity 클래스명과 테이블명이 동일해야 매핑이 되는데

동일하지 않을경우 설정해주는 어노테이션

 

@SequenceGenerator

속성 명 설명
name 실벽자 생성기의 이름 ( 필수 ** )
sequenceName 데이터베이스에 등록된 시퀀스 명
(DEFAULT : hibernate_sequence)
initialiValue 시퀀스의 시작값, 최초 생성시 사용된다
(DEFAULT : 1 )
allocationSize 시퀀스 호출시마다 증가하는 값, 성능최적화에 사용되며
데이터베이스 시퀀스 값이 1씩 증가한다면
반드시 1로 지정해야 한다

 

@Id

PRIMARY KEY를 알려주는 어노테이션

필수속성!! ( 이걸 생성해야 Entity 빨간밑줄이 사라진다 )

 

@GeneratedValue

속성값 설명 대표DBMS
strategy = GenerationType.IDENTITY 기본키 생성을 데이터베이스에 위임.  MYSQL
strategy = GenerationType.SEQUENCE 시퀀스 사용, @SequenceGenerator 필요(시퀀스 생성) ORACLE
strategy = GenerationType.TABLE 키 생성용 테이블 사용, @TableGenerator 필요 모든 DBMS
strategy = GenerationType.AUTO 데이터베이스 방언에 따라 자동 지정(기본값)  

현재 실습은 Oracle을 사용하고 있으므로 " SEQUENCE 전략 " 을 사용할 예정

( MySQL도 공부하고 있으므로 " IDENTITY 전략 " 도 공부할 예정 )

 

" SEQUENCE 전략 "

@GeneratedValue 속성 strategy = GenerationType.SEQUENCE와 함께사용하는 generator 속성에

@SequenceGenerator 을 이용하여 DB에 생성되어있는 시퀀스를 저장한 ( name="BOARD_SEQ" )을

대입하여 사용한다

 

 


위에 저장된 내용을 가지고 사용해 봅시다

 

11 라인 EntityManagerFactory객체를 이용하여 JPA 설정파일을 가져옵니다

 

( JPA 설정파일 - persistence.xml )

 

12 라인 꺼내온 설정파일을 EntityManager 객체에 emf.createEntityManager()로 담아주고 사용합니다

 

**13 라인 트랜잭션으로도 사용할 수 있습니다 ( 롤백 가능 )

 

16 라인 et.begin(); 을 이용하여 트랜잭션의 시작을 알립니다

 

18 라인 Entity클래스인 Board를 불러와 객체화 합니다

 

19 라인 setter를 이용하여 저장할 내용을 작성합니다

( bid = 시퀀스를 이용하여 자동으로 1씩 증가하도록 설정 되어있는 상태 )

 

23 라인 em.persist(Entity객체)

엔티티 매니저를 사용해 엔티티객체를 영속성 컨텍스트에 저장한다는 의미!

 

em.persist 관련 참고 블로그 자료

 

JPA 영속성 컨텍스트란?

영속성 컨텐스트란 엔티티를 영구 저장하는 환경이라는 뜻이다. 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.em.persist

velog.io

 

 

Select >> update, delete || insert 

 

처음으로 데이터가 존재하는지 Select를 실행해주고

( 안전하게 해당 데이터가 존재하는지 여부를 먼저 확인함 )

 

PK로 존재 여부를 확인하여 이에 따라 update와 delete || insert를 실행해준다

PK가 존재하지않기때문에 insert만 실행된다 

( update와 delete는 추가적으로 공부해야할 예정 )

 

26 라인 et.rollback() 에러가 발생한다면 CRUD를 롤백해 준다

 

30, 31 라인 생성순서 반대로 Manager를 닫고 팩토리를 닫아준다

 

실행결과

JPA 설정에서 선택옵션으로 로그를 띄우도록 설정하여 볼 수 있는데

**select를 먼저 하는 모습을 볼수 있다

 

DB에도 잘 들어가고 있는 모습니다

 

 

참고할 테이블 설정, 시퀀스 설정이다

 

 


오류 발견 및 해결방법

 

JPAClient를 실행시 발생한 에러

pom.xml에 dependency를 추가하여 해결

 

 

참고 블로그

 

java.lang.NoClassDefFoundError 해결 방법 : javax / xml / bind / JAXBException

질문 : java.lang.NoClassDefFoundError 해결 방법 : javax / xml / bind / JAXBException Java 6/7/8에서 JDK의 일부로 제공되는 JAXB API 클래스를 사용하는 코드가 있습니다. Java 9로 동일한 코드를 실행하면..

rateye.tistory.com

 

 

 

시퀀스를 DROP하고 다시 생성하여 실행했을 경우

@SequenceGenerator 에 의해 시퀀스 값이 1씩 증가하고있다

이 시퀀스를 DROP하여 다시 생성하면 1부터 시작하게 되므로

PK중복 현상이 일어나 나타난 오류이다

 

해결방법으로는 이전 테이블에 저장된 PK 마지막번호를 이용하여 설정할 수 있는 방법이 있을 것 같다

라고 생각만하지만.. 아직은 기초다 보니 뚜렷한 해결할 방법은 아직 모르겠습니다.

 

그래서 공부해볼 예정이고 현재로서는

 

- Board 테이블을 삭제하고 새로만들어서 새로만든 시퀀스와 같이 사용하거나

- @SequenceGenerator에 설정한 초기값을 1이 아닌 PK 마지막번호에서 +1 값을 적는 것이

 

지금 내 기초레벨의 해결 방법이 아닐까 싶다

 

 

 

 

Main 메소드 실행시 경고문구 발생

버전호환에 따른 경모문구로서 로직이 실행되는데에 문제가 생기는 에러는 아니지만 불편하다...

 

pom.xml 에서 버전들을 호환성있게 잘 맞춰줘야 경고문구가 사라진다

검색해보니 WARNING 문구중 2번째 줄을 확인하여 해결하는 것이 해결 방법이 되겠다

( 해결은 못함.. 로직은 돌아가니까.. 나중에 고쳐보자 )