[Java] JPA 기초 탐색하기

programmeaow·2022년 6월 15일
0

Java

목록 보기
13/13

✔️ JPA란?

JPA는 Java ORM 기술의 표준으로 사용되는 인터페이스 모음으로, 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이다.
대표적으로는 Hibernate가 있다.

그런데, ORM은 대체 무엇일까?

- ORM (Object Relational Mapping)

: 객체와 관계형 데이터베이스를 연결한다는 의미

JPA는 자바 객체와 관계형 데이터베이스를 연결시 사용하는 방식을 정의한 인터페이스라고 해석할 수 있다!

- JPA의 장점

  1. SQL 문장이 아닌 메서드를 통해 DB를 조작할 수 있게 해준다. 따라서 DB중심의 설계가 아닌, 객체지향적 설계가 가능해진다.

  2. 특정 DB에 종속되지 않는다.
    - DB별로 조금씩 다른 문법 등을 고려하지 않아도 된다는 장점이 있다.
    - DB 종속적인 기능을 많이 이용하는 경우를 고려해 다양한 방언 클래스를 제공한다.

    방언이란?

    : DBMS마다 조금씩 문법의 차이가 발생하는데 이런 문법적 차이가 발생하는 부분을 방언이라고 한다.

  3. 유지보수 및 구조변경에 용이하다.

    • 필드 변경 시 모든 SQL 문장을 수정할 필요 없이 필드만 추가하면 된다.
  4. 생산성 향상이 가능하다.






✅ JPA 환경설정

JPA를 사용하기 위해서는 먼저 Java ProjectJPA Project로 변경해야 한다.

🔹 JPA 프로젝트 변환 방법

  1. Java Project 우클릭 > Configure > Convert to JPA Project

  2. 설정 창에는 JavaJPA 두가지가 선택되어 있을 것이다. 여기서 Java의 버전을 확인한 뒤 바꿔주자.

    • 기본 값이 Java 16으로 설정되어 있는데 현재 11버전을 이용중이라 바꿔주었다.
  3. Details 옆의 Runtimes를 클릭한 뒤, jre를 체크한다.

    • JPAJava가 잘 체크되어 있는지, 버전은 현재 사용중인 자바 버전과 동일한지 최종 확인한 후 Next를 두 번 눌러준다.
  4. JPA implementationTypeDisable Lirary Configuration으로 바꿔준 뒤 Finish 한다.


설정이 완료 되었다면 Java Project의 src 하단에 META-INF라는 폴더가 생기며 해당 폴더 안에 persistence.xml이라는 설정 파일이 생긴다.

해당 파일을 오픈한 뒤 source를 클릭하면 설정을 변경할 수 있다.



🌟 JPA 사용하기

JPA를 이용하여 테이블을 생성하고 데이터 CRUD 작업을 수행하려면 데이터베이스의 Table과 대응하는 Entity 클래스를 생성한 뒤 EntityManager 설정, 트랜잭션 관리, 비즈니스 로직을 구성해줘야 한다.

여기서 생소한 단어가 여러가지 등장한다.
먼저, Entity는 무엇을 의미하는 걸까?

❓. Entity

데이터베이스의 테이블과 대응하는 하나의 클래스

영속성을 가진 객체로 DB Table에 보관할 대상(혹은 영속 컨텍스트에 보관할 대상)이라고도 한다.

데이터베이스와 대응?

Oracle에서 학습용으로 제공한 Table인 emp 를 예시로 들어보자.

DB에 emp Table과 Java에 emp Class가 존재한다고 하면, emp Tableemp.java Class 의 대응 관계를 가지게 된다.


@Entity 어노테이션을 붙이면 테이블과 Java 클래스가 연결(매핑)이 된다.
예시로 Java에서 Student 테이블을 만들어보자.

@Entity
public class Student {
	private int student_no;
	private String student_name;
	private String grade;
}

DB의 Student 테이블과 매핑될 Java 클래스가 생성되었다.
만약 DB 테이블과 Java 클래스의 이름이 다르면 @Table 어노테이션을 사용하면 된다.

@Entity
@Table(name="Student") 	//이름을 "Student"로 설정
public class Test {
	private int student_no;
	private String student_name;
	private String grade;
}

Test Class를 새로 생성한 뒤 EntityManager를 이용하여 DB에 Student Table을 새로 생성해볼 것이다.

멤버변수 초기화 메서드와 @Getter, @Setter 외의 설정을 추가하여 코드를 마저 작성했다.

🍋 어노테이션 기능 알아보기

@requiredargsconstructor : @NonNull이 붙은 필드의 생성자를 추가
@NonNull : Null을 허용하지 않을 경우
@Id : PK ( Primary Key, 기본 키 ) 지정
@GeneratedValue : 기본키 설정을 DB에 위임하는 방식, @Id와 함께 사용해야 하며 DB가 자동으로 AUTO_INCREMENT 적용함

(strategy = GenerationType.IDENTITY) : persistence provider가 DB의 identity 컬럼을 이용하여 자동 생성하겠다는 의미

@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Getter
@Setter
@ToString

@Entity
public class Student {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int student_no;
	@NonNull
	private String student_name;
	@NonNull
	private String grade;
}


Test라는 이름의 클래스를 새로 생성한 뒤 JPA를 사용해서 Student 테이블을 생성해보자.
먼저 DB 작업을 위해 다음과 같은 코드를 작성했다.

public class RunningTest {

	public void Test() {
    
	EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQLDB");
	EntityManager em = emf.createEntityManager();
	EntityTransaction tx = em.getTransaction();
	tx.begin();

	tx.commit();
    
    }
}

EntityManagerFactory , EntityManager , EntityTransaction 은 무엇일까?


❓. EntityManagerFactory

EntityManager 인스턴스를 관리하는 객체

EntityManagerFactory 는 생성 비용이 아주 크기 때문에, 어플리케이션 실행시 하나만 생성한 뒤 공유하여 사용한다.
사용자가 요청시 EntityManagerFactoryEntityManager를 생성한다.

✔️ 어플리케이션 종료시 EntityManagerFactoryClose로 종료해줘야 한다.


코드를 한번 살펴보자.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQLDB");
  1. EntityManagerFactory 객체인 emf 를 생성한다.
  2. PersistenceMETA-INF 폴더의 persistence.xml 내부의 설정 정보를 조회한다.
  3. persistence.xml 에서 조회한 정보를 바탕으로 EntityManagerFactory 를 생성한다.
  4. EntityManagerFactoryEntityManager 를 생성한다.

❓. EntityManager

Entity에 대한 DB 작업을 제공하는 객체

EntityManager는 내부적으로 DB Connection을 이용하여 DB에 접근한 뒤, EntityManager를 통해 CRUD 작업이 가능하게 해준다.
= EntityManager를 통해 Persistence Context(영속성 컨텍스트) 에 접근하여 DB 작업을 제공한다.

Persistence Context : Entity를 영구 저장 가능하게 지원하는 환경

어플리케이션 구동시 EntityManagerFactory 를 생성하고 EntityManagerFactory 는 사용자가 요청시 EntityManager 를 생성한다.
DB에 작업이 가능하려면, DB 작업을 제공하는 객체인 EntityManager 객체를 생성해줘야 한다.

다시 코드를 살펴보자.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQLDB");
EntityManager em = emf.createEntityManager();

EntityManager 객체 emEntityManagerFactory 객체인 emfemf.createEntityManager() 를 통해 생성된 것을 확인할 수 있다!

이제 트랜젝션을 시작하여 DB에 작업을 요청할 수 있다.


❓. EntityTransaction

트랜잭션(Transaction) : 데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위

트랜젝션은 DB의 상태를 변화시키기 위해 수행하는 작업, 즉. DB 작업을 뜻한다.

따라서 EntityTransaction 은 DB 작업을 시작하기 위해 DB 작업을 제공하는 객체인 EntityManager로부터 트랜젝션 API를 가져와야 한다.

코드를 다시 살펴보자.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQLDB");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();

tx.begin();
tx.commit();

EntityTransaction 객체인 txEntityManager 객체인 em 으로부터 트랜젝션을 가져오는 것을 볼 수 있다.

이 흐름을 도식화하면 이런 그림이 되는 것이다.


이제 코드를 실행하여 Student Table을 생성해보자.

public class RunningTest {

	public void Test() {
    
	EntityManagerFactory emf = Persistence.createEntityManagerFactory("MySQLDB");
	EntityManager em = emf.createEntityManager();
	EntityTransaction tx = em.getTransaction();
	tx.begin();

	tx.commit();
    
    }
}

코드 실행 후, cmd에서 MySQL에 접속하여 생성된 테이블 목록을 show tables; 로 확인해보았다.

정상적으로 생성된 것을 확인했다!

desc student; 명령어를 통해 Table의 속성을 확인해보자.

Student 클래스에서 생성한 컬럼들이 전부 있는 것을 볼 수 있다.
student_no 에 적용한 PK 설정과 AUTO_INCREMENT 도 적용되어 있다.

이제 Student 클래스에 새로운 데이터를 추가해보자.
학번은 AUTO_INCREMENT를 적용하여 입력하지 않아도 되므로 [ Louis, 1학년 ] 을 추가할 것이다.

@Test
public void Test() {
		
	EntityManagerFactory emf = Persistence.createEntityManagerFactory("dbinfo");
	EntityManager em = emf.createEntityManager();
	EntityTransaction tx = em.getTransaction();
	tx.begin();
		
	Student student1 = new Student("Louis", "1학년");
	em.persist(student1);  
		
	tx.commit();
}

DB에 CURD 작업을 수행하려면 .persist() 를 사용하여 영속성 컨텍스트에 데이터를 넣어준다.
이후 commit 이 실행되면서 DB에 Insert한 데이터가 반영되는 것이다.

데이터 추가 로직을 MYSQL 문장으로 입력하면 다음과 같다.

Insert into Student VALUES ('Louis', '1학년');


DB에 데이터가 추가된 것을 확인할 수 있다.

이번에는 "Louis"의 학년을 2학년으로 Update 해보자.

tx.begin();
		
Student student1 = new Student("Louis", "1학년");
student1.setGrade("2학년");
em.persist(student1);  
		
tx.commit();


"Louis"의 grade가 2학년으로 변경된 것을 확인할 수 있다.

쿼리 문장을 실행하려면 createQuery 안에 SQL 문장을 입력해야 한다.
일반 SQL 문장이 아닌 JPQL 쿼리문으로 Select 문을 작성하고 Student 클래스에 있는 모든 데이터를 출력해보자.

em.createQuery(jpql, Member.class) : 해당 메서드의 Member.class 부분에는 조회하려는 데이터의 자료형 클래스를 입력해주면 된다.

⭐ JPQL

객체지향 쿼리 언어로 Table이 아닌 Entity를 대상으로 한다.

일반 쿼리 문장과 JPQL 쿼리 문장은 거의 똑같지만 일부 차이점이 있다.
JPQL 작성 문법에 대해 알아보자! 예시로 Select 문을 작성한다고 하면,

select 별칭 from 테이블명 별칭

위와 같이 작성할 수 있다.

DB의 Table을 대상으로 찾는 것이 아닌 Entity를 대상으로 하기 때문에 별칭이 필수로 들어가며, @Entity 어노테이션이 붙은 테이블 명과 대소문자를 동일하게 작성해주어야 한다.

Student 클래스로 일반 SQL 쿼리문과 비교를 해보자.

//MySQL
select * from student;

//JPQL
select s from Student;

JPQL 문법을 바탕으로 select 문장을 적용시켜보았다.

List<String> studentList = em.createQuery("select s from Student s").getResultList();
System.out.println(studentList);


Student 클래스에 존재하는 데이터인 Louis의 정보가 출력되었다.


마지막으로 Louis 데이터에 Delete를 적용해보자.
em.remove(student1);

해당 문장 실행 후 cmd에서 Student 클래스를 조회하면 다음과 같이 출력된다.

mysql> select * from student;
Empty set (0.00 sec)



profile
개발이란 뭘까

0개의 댓글