일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 값 타입 컬렉션
- Bean Validation
- JPA 활용 2
- 예제 도메인 모델
- 트위터
- 로그인
- QueryDSL
- 스프링
- jpa 활용
- 불변 객체
- JPA 활용2
- 스프링 데이터 JPA
- 컬렉션 조회 최적화
- 벌크 연산
- API 개발 고급
- 실무활용
- 타임리프
- JPA
- 임베디드 타입
- 검증 애노테이션
- 페이징
- 일론머스크
- 스프링MVC
- 김영한
- Spring Data JPA
- 타임리프 문법
- 프로젝트 환경설정
- 스프링 mvc
- 기본문법
- JPQL
- Today
- Total
RE-Heat 개발자 일지
[JPA] [2] JPA 시작 - 프로젝트 생성 및 개발 본문
https://www.inflearn.com/course/ORM-JPA-Basic
인프런 김영한 님의 강의를 듣고 작성한 글입니다.
[1] Hello JPA - 프로젝트 생성
■ 프로젝트 생성
▶ H2 데이터베이스
① 장점
- 최고의 실습용 DB
- 가볍다.(1.5M)
- 웹용 쿼리툴 제공
- MySQL, Oracle 데이터베이스 시뮬레이션 기능
- 시퀀스, AUTO INCREMENT 기능 지원
② 설치방법 (윈도우 기준)
1] Windows Installer를 다운받고 실행
2] 설치된 곳(예 C:\Program Files(x86)\H2\bin)의 h2.bat 파일 cmd창에서 실행
3] 예전에 설치했다가 지웠던 사람은 초기화 필요
https://gocoder.tistory.com/2536
C:\Users\사용자이름"에서 test.trace.db, test.mv.db 파일 삭제
h2.server.properties 파일은 메모장으로 열어서 변경(자세한 코드는 위 링크에서 확인)
▶ Maven
장점
자바 라이브러리, 빌드 관리
라이브러리 자동 다운로드 및 의존성 관리
단점
최근에는 그래들(Gradle)이 점점 유명
=> 그동안 사용하던 그래들을 쓰려고 했으나, xml 방식을 안 쓴 지 오래된 관계로 강의 따라서 Maven 쓰기로 결정
▶ JAVA 11(JAVA 8 이상)
강의의 세팅을 그대로 사용하면 JAVA 11이 호환이 되지 않을 때가 있다.
특히 javax.xml.bind.JAXBException 에러가 발생할 수 있는데, 그럴 땐 pom.xml에 아래와 같은 디펜던시를 추가해 주면 된다.
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
https://www.inflearn.com/questions/13985/java11-javax-xml-bind-jaxbexception-%EC%97%90%EB%9F%AC
=> 참고한 링크
▶ IntelliJ 설정① Maven 설정
- groupId: jpa-basic
- artifactId: ex1-hello-jpa
- version: 1.0.0
② pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<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>2.2.220</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
</project>
1] 하이버네이트 버전 : 5.3.10.Final
2] H2 데이터베이스 버전 : 2.2.220
※ 주의 : 실제로 다운받은 H2 데이터베이스 버전을 써줘야 한다!
3] JAVA 11을 사용하면 javax.xml.bind를 디펜던시에 추가해줘야 한다.
4] Error:java: error: release version 5 not supported가 뜨면 특정 JDK 버전으로 빌드해야 하므로 'maven compiler plugin'을 추가해야 한다. <build>... </build> 안에 추가된 부분이다.
③ persistence.xml
- JPA 설정 파일
- /META-INF/persistence.xml 위치
- persistence-unit name으로 이름 지정
- javax.persistence로 시작: JPA 표준 속성
- hibernate로 시작: 하이버네이트 전용 속성
<?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.Oracle8iDialect"/>
<!-- 옵션 -->
<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.jdbc.batch_size" value="10"/>-->
<!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
유의사항
1] java.persistence.jdbc.url은 localhost:8082를 치면 뜨는 H2 데이터베이스 설정과 일치시켜야 한다.
2] hibernate.dialect는 데이터 베이스 방언을 세팅. 오라클, H2, MySQL 등을 선택할 수 있다.
■ 데이터베이스 방언
① 데이터베이스 방언이란?
• JPA는 특정 데이터베이스에 종속돼 있지 않다.
• 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다르다.
예시
가변문자 : MySQL은 VARCHAR, Oracle은 VARCHAR2
문자열을 자르는 함수 : SQL 표준은 SUBSTRING(), Oracle은 SUBSTR()
페이징 : MySQL은 LIMIT , Oracle은 ROWNUM
• JPA는 DBMS별로 조금씩 다른 SQL방언을 해결하기 위해 Dialect라는 추상화된 방언 클래스를 제공한다.
② pom.xml에 dialect 속성 지정 방법
주요 RDBMS
• H2 : org.hibernate.dialect.H2Dialect
• Oracle 10g : org.hibernate.dialect.Oracle10gDialect
• MySQL : org.hibernate.dialect.MySQL5InnoDBDialect
하이버네이트는 40가지 이상의 데이터베이스 방언을 지원한다.
[2] Hello JPA - 애플리케이션 개발
■ JPA 구동방식
① Persistence에서 설정 정보를 조회하는 곳은 META-INF/persistence.xml이다.
② persistence.xml에서 설정정보를 조회한 후 EntityManagerFactory를 생성
③ EntityManagerFactory는 EntityManger라는 클래스를 생성해서 사용한다.
■ 실습 - JPA 동작확인
JPA Main
EntityManagerFactory emf = Persistence.createEntityManager("hello");
EntityManager em = emf.createEntityManager();
//code
em.close();
emf.close();
EntityManagerFactory를 만들 때 persistence.xml의 name과 꼭 일치시켜야 한다.
객체와 테이블을 생성하고 매핑하기
① H2 데이터베이스에서 Member 테이블 생성
② Member 클래스 생성
Member
1] @Entity로 지정해 줘야 한다. 추가로 @Table(name=)을 넣어주면 매핑할 테이블의 이름을 지정할 수 있다. 없으면 class명으로 만든다.
2] @Id로 기본키를 지정해야 한다.
3] @Column(name="username") 만일 칼럼명이 username이면 이렇게 지정해 줘야 알맞게 값이 들어간다.
4] getter와 setter도 필요하다.
■ 실습 - 회원 저장
① 회원 등록
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(2L);
member.setName("HelloB");
em.persist(member);
tx.commit();
}catch (Exception e){
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
1] EntityTransaction tx = em.getTransaction() : DB 데이터 등록 변경 등은 트랜잭션 내에서 이루어져야 한다.
tx.begin() : 트랜잭션 시작
tx.commit() : 트랜잭션이 성공적으로 마무리됐고 DB가 일관성이 있을 때 트랜잭션이 끝났다는 것을 알려주기 위한 연산
tx.rollback() : 비정상적으로 종료돼 원자성이 깨진 경우 트랜잭션을 처음부터 시작하거나 연산 결과를 취소시킨다.
=> 원자성 : 트랜잭션이 DB에 모두 반영되든가 전혀 반영되지 않아야 한다.
참고] 트랜잭션 예시
게시판 사용자가 게시글을 작성 후 등록버튼을 누른다. 이후 자신의 글이 포함된 게시판을 보게 된다.
insert문(게시글 등록) + 게시판 조회(select) : 이런 하나의 작업 단위가 하나의 트랜잭션이다.
2] Member객체에 id와 name 세팅
3] em.persist(member)로 db에 등록
=> 엄밀히 말하면 엔티티를 영속성 컨텍스에 저장하는 것이다.(다음 챕터에서 설명)
4] EntityMangerFactory와 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();
try{
Member findMember = em.find(Member.class, 1L);
System.out.println("findMember.getId() = " + findMember.getId());
System.out.println("findMember.getId() = " + findMember.getName());
tx.commit();
}catch (Exception e){
tx.rollback();
} finally {
em.close();
}
emf.close();
//code
em.close();
emf.close();
}
}
1] em.find()를 쓰면 select문이 날아간다. (1L이라는 아이디를 가진 값이 있다고 가정)
③ 회원 삭제
Member findMember = em.find(Member.class, 1L);
em.reomve(findMember);
db에서 삭제하려면 em.remove()를 쓰고 해당 객체를 넣으면 된다.(id가 아닌 객체 전체)
④ 회원 수정
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction(); //JPA 안 모든 변경은 transaction 안에서 이뤄져야 함.
tx.begin();
try{
Member member = em.find(Member.class, 150L);
member.setName("ZZZZZ");
System.out.println("============");
tx.commit();
}catch (Exception e){
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
1] member를 찾은 후 setName으로 이름을 교체
2] update 쿼리가 날아가는 것을 확인할 수 있다.
JPA에선 트랜잭션 커밋하기 전 엔티티와 스냅샷(값을 읽어온 최초 시점)을 비교하고 바뀐 부분이 있다면 update 쿼리를 날린다.
=> 자세한 내용은 [3] 영속성 관리에서 확인
■ JPQL 소개
• JPA를 사용하면 엔티티 객체를 중심으로 개발
• 문제는 검색 쿼리
• 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
• 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
• 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요
그래서 만들어진 게 JPA에서 SQL 역할을 하는 JPQL
① JPQL로 전체회원 검색
1] List<Member> result = em.createQuery("select m from Member as m", Member.class).getResultList();
JPQL로 Member 클래스의 전체 회원 검색
2] for문으로 전체회원의 이름 로그창에 찍기
3] select 쿼리문이 날아가는 걸 확인할 수 있다.
② JPQL로 까다로운 pagination도 손쉽게 가능
페이징 : 조회된 결과를 몇 번째부터 몇 개씩 가져올지 정하기
setFirstResult(1) : 시작위치는 첫 번째부터
setMaxResults(10) : 시작위치부터 10개씩 가져오기
③ 데이터 방언 바꿔보기 (H2=>Oracle)
오라클로 바꾸면 Pagination을 rownum으로 하는 것을 확인할 수 있다(JPA가 각 DBMS에 맞게 알아서 처리해 줌).
JPQL은 [10], [11] 객체지향 쿼리 언어에서 더 자세히 다룰 예정이다.
'백엔드 > JPA' 카테고리의 다른 글
[JPA] [4] 엔티티 매핑(하편) - 기본키 매핑 (0) | 2023.08.06 |
---|---|
[JPA] [4] 엔티티 매핑(상편) (0) | 2023.08.05 |
[JPA] [3] 영속성 관리 - 내부 동작 방식 (0) | 2023.08.04 |
[JPA] [1] JPA 소개 - JPA는 무엇인가? (0) | 2023.08.03 |
[JPA] [1] JPA 소개 - SQL 중심적 개발의 문제점 (0) | 2023.08.03 |