자바 JPA(Hibernater)적용하기
자바 JPA(Hibernater)적용하기 — #자바 #JAVA #자바Hibernate #자바하이버네이트 #자바JPA적용 #JAVAJPA적용 #개발자의도구...
#자바 #JAVA #자바Hibernate #자바하이버네이트 #자바JPA적용 #JAVAJPA적용 #개발자의도구들
🚨📝 📖 📒
AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니다
\* 현재 Spring 프로젝트를 진행 중입니다. 전체적인 목차를 보시려면 여기를 눌러주세요.
사실 Hibernate는 JPA의 원조이다
JPA스펙에 대해 공부한바 있는데요. 사실 이 스펙은 Hibernate를 보고 만들어진 스펙입니다. JAVA에서는 이렇게 사용자가 만든 라이브러리가 공식 스펙으로 되는 경우가 많습니다.
Red hat에서 개발한 오픈소스 ORM 프레임워크였다가, 기술이 좋아서 JAVA가 이를 참고하여 표준 JPA명세를 만들었습니다.
그렇다고 JPA와 Hibernate가 완전 동일하다고느 ㄴ할 수 없습니다. JPA는 단순 명세(스펙)를 나열한 것이고, 그 명세대로 구현된 것이 Hibernate라고 보면 됩니다. (싸실은 반대지만... ). 그러니 JPA를 구현한 또 다른 프레임워크가 존재한다는 것이죠.
Hibernate 적용하기
\* gradle 프로젝트 기준으로 설명하겠습니다.
환경 샛탕
의존성 추가
build.gradle
| // JPA APIimplementation 'jakarta.persistence:jakarta.persistence-api:3.1.0' // JPA API// JPA 구현체implementation 'org.hibernate:hibernate-core:6.2.5.Final' // Hibernate Core (JPA 구현체) |
|---|
| 💡JAVA JPA의 버전 Isuue(javax vs jakarta) 만약 import에 javax가 들어가 있따면 JPA버전이 2.2이하인 경우입니다. 예전에 사용하던 버전으로 여전히 많은 프로젝트에서 사용되기는 하지만, 최신 버전을 사용하려면 JPA 2.3 이상의 버전을 사용하세요. 최신 버전에는 jakarta. 가 import됩니다. ex) import jakarta.persistence.\* ; |
|---|
파일 설정
project내부 direcotry경로/src/main/resource/META-INF(없으면 만들기)
persistence.xml
| <?xml version="1.0" encoding="UTF-8"?><persistence 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" version="2.2"> <!-- EntityManager를 Hibernater로 등록--> <persistence-unit name="onlyJPAUnitt" transaction-type="RESOURCE\_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <!-- DB연결 --> <property name="javax.persistence.jdbc.url" value="jdbc:mariadb://localhost:3306/http?useSSL=false"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="pw"/> <property name="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MariaDBDialect"/> <property name="hibernate.show\_sql" value="false"/> <property name="hibernate.format\_sql" value="true"/> <!-- Configuration for connection pool (HikariCP)--> <property name="hibernate.hikari.connectionTimeout" value="20000"/> <property name="hibernate.hikari.minimumIdle" value="10"/> <property name="hibernate.hikari.maximumPoolSize" value="10"/> <property name="hibernate.hikari.idleTimeout" value="300000"/> <property name="hibernate.hikari.poolName" value="SpringBootJPAHikariCP"/> </properties> </persistence-unit></persistence> |
|---|
주석으로 관련 설정들을 달아뒀으니 여러분들의 환경에 따라 변경하시며 됩니다!
| 🚧 위 설정 파일은 yaml으로 대체되었으니 여기를 참고해주세요. |
|---|
Entity 정의
jPA는 기본적으로 ORM입니다. 이는 JAVA에서 Obejct를 만들면 JPA가 알아서 내가 연결한 DB의 Table과 maaping을 해줍니다.
우리는 그럼 Class를 만들면 되겠죠? 어떻게 만드는지 아래 코드를 봅시다.
package com.example.webserver.entity;import jakarta.persistence.\*;import java.time.LocalDateTime;import java.util.List;@Entitypublic class BoardEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="id") private long boardId; @Column(name = "title", nullable = false) private String title; @Column(name = "writer", nullable = false) private String writer; @Column(name = "writing\_time", nullable = false) private LocalDateTime writingTime; @Column(name = "reading\_count", nullable = false) private Integer readingCount; @Column(name = "text\_content", nullable = false) private String textContent; @OneToMany(mappedBy = "board") private List<CommentEntity> comments;} |
|---|
| package com.example.webserver.entity;import jakarta.persistence.\;import lombok.Data;import lombok.extern.slf4j.Slf4j;import java.time.LocalDateTime;@Entity@Slf4j@Table(name = "comments")@Datapublic class CommentEntity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY*)@Column(name="id")private long commentId;@ManyToOne@JoinColumn(name="board\_id")private BoardEntity board;@Column(name="writer")private String Writer;@Column(name="writing\_time")private LocalDateTime writingTime;@Column(name="text\_content")private String textContent;} |
|---|
- @Entoty로 선언된 class는 DB의 테이블에 매칭이됩니다
- table에는 각 column이 존재하죠? 이는 class의 feild에 매핑됩니다.
- @id는 table의 primary Key를 지정하는데 사용됩니다. ( clas는 반드시 하나의 @id feild가 존재 해야 합니다. )
- @GenerateValue를 사용하여 AUTO INCREMENT로 column 속성을 변경할 수 있습니다.
- @oneToMany / @ManyToOne을 사용하여 1:M 관계를 정의합니다. (comment에 boardId가 외래키로 참조 중)
boards / comments
실제 DB의 모습은 이렇습니다.
더 많고 자세한 어노테이션(@)은 JPA스펙 글에 정리를 해두었씁니다.(쭈기적으로 업데이트 해볼게요.
\* 추가정보
- @table을 @Entity와 사용하면 테이블 이름을 다르게 지정하거나 스키마 등의 추가 설정이 가능합니다.
- 나머지는 그때 그때 찾아보세요!
EntityManger 설정
JPA의 경우 EntityMager를 꼭 구현해줘야 하는데, 저희는 Hibernater를 사용하고 있으니, EntityMager로 Hibernater에서 구현된 객체를 사용하겠다고 알려줘야 합니다. 사실 이건 위의 xml에서 적용된 부분입니다.
| <persistence-unit name="onlyJPAUnit" transaction-type="RESOURCE\_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> |
|---|
persistenc-unit으로 이미 Hibernater를 적용했고 이름도 "onlyJPAUnit"으로 지정해두었네요. 우리는 이제 EntityMager를 불러서 사용하면됩니다.
기본적으로 MSC 모델을 사용하고 있기 때문에 Model에 해당하는 Repository를 구현 해봅시다.
package com.example.webserver.repository;import com.example.webserver.entity.BoardEntity;import java.util.List;import java.util.Optional;public interface BoardRepository { List<BoardEntity> findAll(); Optional<BoardEntity> findById(long id); void removeById(long id); void save(BoardEntity board);} |
|---|
| package com.example.webserver.repository;import com.example.webserver.entity.BoardEntity;import lombok.extern.slf4j.Slf4j;import jakarta.persistence.\*;import java.util.List;import java.util.Optional;@Slf4jpublic class BoardRepositoryImpl implements BoardRepository { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("onlyJPAUnit"); EntityManager entityManager = entityManagerFactory.createEntityManager(); @Override } |
|---|
interface로 선언 후 상속받아서 이런 패턴으로 구현해주면 됩니다!
- EntityManger를 선언하려면 EntityMagerFactory(JPA꺼)에서 hibernater에서 만든 EntityManger를 불러옵니다. (xml 파일에서 설정한 unit이름을 넣어요)
- 이후 EntityManger를 선언해주면 됩니다. (.createEntityManager() )
CRUD 연산 사용해보기
기본적으로 JPA는 CRUD연산을 지원해줍니다. 근데 복잡한건 지원해주지 않아요. 이때는 JPQL을 사용해야 하는데, 이부분은 나중에 따로 다뤄보도록 하겠습니다.
package com.example.webserver.repository;import com.example.webserver.entity.BoardEntity;import java.util.List;import java.util.Optional;public interface BoardRepository { List<BoardEntity> findAll(); Optional<BoardEntity> findById(long id); void removeById(long id); void save(BoardEntity board);} |
|---|
아까 Repository에서 만들어둔 CRUD 연산만을 구현해 보겠습니다.
package com.example.webserver.repository;import com.example.webserver.entity.BoardEntity;import lombok.extern.slf4j.Slf4j;import jakarta.persistence.\;import java.util.List;import java.util.Optional;@Slf4jpublic class BoardRepositoryImpl implements BoardRepository { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("onlyJPAUnit"); EntityManager entityManager = entityManagerFactory.createEntityManager(); @Override public List<BoardEntity> findAll() { return null; } @Override public Optional<BoardEntity> findById(long id) { return Optional.of*(entityManager.find(BoardEntity.class, id)); } @Override public void removeById(long id) { entityManager.remove(id); }; @Override public void save(BoardEntity board){ entityManager.persist(board); };} |
|---|
- persist(Entity)는 매핑되는 Entity class를 테이블에 저장해 줍니다. (C)
- find(Entity.class, id)는 id를 통해 Entity를 조회해주는 메서드입니다.(R)
- remove(id) 는 id를 통해 Entity를 제거해주는 메서드입니다. (D)
- findAll()은 전체 BoardEntity를 조회하는건데, 이는 기본적으로 지원해주지 않습니다.
총 정리
이제 JPA에 대해 조금은 감이 오시리라 생각됩니다. 오늘 내용을 정리해보자면 다음과 같습니다.
- 결국 JPA는 DB와의 연결을 통해 데이터를 쉽게 조작하기 위해 만들어졌다.
- JPA는 method를 미리 구현해 두어 DB에 쿼리를 대신 날려준다. 이 말은 사용자가 직접 query작성 없이도 쉽게 데이터를 조작할 수 있음을 의미한다.
- JPA는 기본적인 CRUD를 method만을 지원한다. 더 복잡한 Query를 만들려면 JPQL을 사용할 수 있다.(다른 것도 있어요)

