[JPA] InteliJ + gradle + SpringBoot + h2 DB(or MySQL) 로 간단 CRUD 기능 구현하기 (2.JPA 시작)
자바 ORM 표준 JPA 프로그래밍 2장 실습+응용입니당 :3
책에 적힌 실습은 환경이 eclipse, maven 기반이라 내 환경에 맞춰 재구성해보았다.
내 환경 : MacOs + InteliJ + Gradle + H2 DB + SpringBoot
(2021.06.29) MySQL로도 적용해보았다.
1. 프로젝트 생성
프로젝트명 : jpa-study
패키지 구성 :
2-1. H2 데이터베이스 설치
H2 Database Engine에서 OS에 맞는 버전을 다운받는다.
압축 파일을 풀면 아래와 같은 파일이 생긴다.
h2 > bin 으로 들어가 jar 파일을 실행시킨다.
h2 웹 브라우저 환경이 뜨면 아래와 같이 URL 경로를 변경하고 연결을 수행한다.
책에 적힌 경로를 먼저 입력하면 오류가 일어날 것이다.
그럼 해당 경로에 test.mv.db 라는 파일이 생성된다. 이후 책에 적힌 경로로 다시 연결을 수행한다.
연결에 성공하면 아래 창에 SQL 문을 입력하여 MEMBER 테이블을 생성한다.
2-2. MySQL 데이터베이스 설치 (feat.도커 사용)
도커를 설치한 후, docker-compose.yml 를 작성한다.
vi docker-compose.yml
version: '3'
services:
local-db:
image: library/mysql:5.7
container_name: local-db
restart: always
ports:
- 13306:3306
environment:
MYSQL_ROOT_PASSWORD: root
TZ: Asia/Seoul
volumes:
- ./db/mysql/data:/var/lib/mysql
- ./db/mysql/init:/docker-entrypoint-initdb.d
docker-compose.yml 이 있는 경로에서 docker 명령어로 서버를 실행한다.
docker-compose up -d
Docker Desktop이 있다면 다음과 같이 local-db 라는 컨테이너가 생성된 것을 확인할 수 있다.
Mysql Workbench 를 설치하고 실행한다.
상단의 docker-compose.yml 파일을 참고해 Connection을 추가한다. 비밀번호는 yml를 따라 root로 설정한다.
아래 쿼리를 실행한다.
create user 'username'@'localhost' identified by 'password';
grant all privileges on *.* to 'username'@'localhost';
flush privileges;
CREATE DATABASE 데이터베이스명 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE 데이터베이스명;
CREATE TABLE MEMBER (
ID VARCHAR(255) NOT NULL,
NAME VARCHAR(255),
AGE INTEGER NOT NULL,
PRIMARY KEY(ID)
);
3. 의존성 추가
// build.gradle
plugins {
id 'org.springframework.boot' version '2.4.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
// ...(중략)...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java' // MySQL 사용
runtimeOnly 'com.h2database:h2' // H2 사용
// ...(중략)...
}
4. application.properties 설정
maven 에서는 persistence.xml 에 해당한다. 스프링 부트를 사용하면 application.properties 또는 applicatin.yml 로 대체할 수 있다.
# H2 디비를 쓴다면 org.h2.Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 도커를 띄웠기 때문에 포트번호가 13306이나 로컬이라면 3306을 사용한다
# H2 디비를 쓴다면 jdbc:h2:tcp://localhost/~/test
spring.datasource.url=jdbc:mysql://localhost:13306/데이터베이스명?serverTimezone=UTC&characterEncoding=UTF-8
# H2 디비를 쓴다면 username, password 둘 다 공란으로 둔다
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.initialization-mode=always
spring.jpa.properties.hibernate.show_sql=true
# H2 디비를 쓴다면 org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.hibernate.use-new-id-generator-mappings=true
5. Main, JpaRunner 설정
- Main
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } }
- JpaRunner
- @PersistContext : 영속성 컨텍스트를 주입하는 어노테이션import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component @Transactional public class JpaRunner implements ApplicationRunner { @PersistenceContext EntityManager em; @Override public void run(ApplicationArguments args) { String id = "id1"; Member member = new Member(); member.setId(id); member.setName("Jihan"); member.setAge(2); // 등록 em.persist(member); // 수정 member.setAge(20); // 한 건 조회 Member findMember = em.find(Member.class, id); System.out.println("findMember= " + findMember.getName() + ", age= " + findMember.getAge()); // 목록 조회 List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList(); System.out.println("members.size=" + members.size()); // 삭제 em.remove(member); } }
- @Transactional : 해당 클래스 내에서 디비 로직 실행 중 에러가 나면 롤백을 해주는 어노테이션. 책에서 try-catch-finally 문을 대신한다고 보면 된다.
- ApplicationRunner : SpringBootApplication이 포함된 프로그램에서 특정 Bean 이 Application 실행 후 실행되도록 하는 인터페이스. - Member 클래스는 책과 동일하다.
- 실행 결과
findMember= Jihan, age= 20
members.size=1
6. 참고 자료
7. 사담
MySQL 를 사용하려고 할 때 root 비밀번호를 까먹어서 애를 먹었다..
기존의 도커 컨테이너를 삭제하고 yml를 다시 실행하니 해결되었다!