ㅅㅇ

[JPA] JPA 구현 및 예제 본문

SW_STUDY/JDBC&JPA

[JPA] JPA 구현 및 예제

SO__OS 2022. 8. 18. 21:18

플레이데이터 빅데이터캠프 공부 내용 

JPA 구현 및 예제

 

1. persistence.xml 

1. 해당 entity class작성

- persistence.xml 파일 - 우클릭해서 아래와 같이 클릭하면, 파일에 아래 코드 자동 생성됨.

 

<class>model.domain.entity.Member</class>

 

@Entity 엑박 시, 거의 이 부분 추가 안해줘서 임.

 

2. create 생성 처리 

 

<property name="hibernate.hbm2ddl.auto" value="create" /> 

    = > create 생성 부터 시작. 만약 기존의 테이블이 있다면, 지웠다가 다시 생성

Hibernate: 
    
    drop table if exists Member

<property name="hibernate.hbm2ddl.auto" value="none" />

    = > create 안함. 기존의 테이블에 데이터 insert

 

2. model.domain.entity 

package model.domain.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;

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

@Entity
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@NonNull
	@Column(length = 10)//, nullable = false)
	private String name;
	
	@NonNull
	@Column(nullable =  true)   
	private int age;
	
	
}

 

1. 생성자 어노테이션

 

어떤 데이터 처리를 할 지에 따라 적절한 파라미터를 보유한 생성자가 생성되어야 한다. 

이를 고려하며, 사용할 생성자을 생각할 수 있어야 한다.  

 

즉, 아래 세 가지 어노테이션 중에서 사용하던,

bulider 을 사용해 직접 원하는 생성자를 만들던,

일단 먼저, 어떠한 속성을 가진 생성자가 생성 되어야 할 지를 먼저 생각해야 한다. 

그래서 entity class 를 작성할 때, 아웃라인 을 잘 체크해야 한다.

 

1) @NoArgsConstructor 어노테이션

 

: 파라미터가 없는 기본 생성자를 생성

 

-  JPA에서 기본 생성자(No-args)가 필요한 이유

구체적인 클래스 타입을 알지 못해도,

그 클래스의 메소드, 타입 변수들에 접근할 수 있도록 해주는 API를 java Reflection 이라 하는데,

Java Reflection API를 사용하면 해당 클래스의 매서드, 맴버 변수, 변수 타입 등을 알 수 있다.


하지만 가져올 수 없는 정보 중 하나가 생성자의 인자 정보들이다.

따라서 기본 생성자가 없다면 

java Reflection은 해당 객체를 생성 할 수 없기 때문에 JPA의 Entity에는 기본 생성자가 필요하다.

 

 

2) @AllArgsConstructor 어노테이션

 

: 모든 필드 값을 파라미터로 받는 생성자를 생성.

 

 

3) @RequiredArgsConstructor 어노테이션

 

: final이나 @NonNull인 필드 값만 파라미터로 받는 생성자를 생성.

 

아래의 코드와 같이 NotNull 이 아닌 필드 값이라면, @RequiredArgsConstructor 로 생성자를 만들 수 없다.

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

@Entity
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@Column(length = 10, nullable = false)
	private String name;

	
	
}

 

 

★ 세 개의 생성자 어노테이션 적용 비교 

 

 

- @NoArgsConstructor 는 필수

 

- @AllArgsConstructor , @RequiredArgsConstructor 에서 둘 중 하나는 꼭 들어가야 하는데,

   어떤 경우에 어떤 것을 써야 할 것인가?

 

         - 일단, pk 를 제외한 모든 필드 값이 NonNull 의 경우  

            @RequiredArgsConstructor 는 꼭 추가해서 pk 를 제외한 파라미터로 이뤄진 생성자가 만들어져야 한다.

            @AllArgsConstructor 있어도 상관없음. 

 

         - 필드값 중 NonNull 이 아닌 변수가 있을 경우, @RequiredArgsConstructor 을 꼭 빼줘야 한다.

            해당 어노테이션은 NonNull 이 아닌 파라미터를 가진 생성자를 생성할 수 없기 때문이다.

            파라미터가 있는 생성자는 꼭 필요하니

            모든 파라미터로 이뤄진 생성자를 생성하는 @AllArgsConstructor 가 있어야 한다.

 

 

객체 생성, 멤버 변수 초기화에서

 

db 의 관점으로 생각했을 때 nonnull 설정, auto 설정 등등 을 위해 JPA 코드를 작성한다면,

 

당연히 객체 생성에 있어 자바에선 인식을 못하고 오류를 낼 것이다. 

 

이를 잘 고려하기 위해서는 생성자가 중요하다. 

 

원하는 JPA 처리를 위해서는 해당 상황에서 적절한 생성자를 쓸 줄 알아야 한다. 

 

  ==> 이때, 객체 멤버 변수 선언 및 초기화 코드를 작성할 때,

outline 에서 생성된 생성자를 확인하고 내가 원하는 코드 작성할 수 있는 지 확인해보자.

 

 

2. 여러 경우에서 JPA 예제

 

1) pk 에 auto increment 를 설정하고, 모든 필드값을 NonNull 설정 시

@RequiredArgsConstructor 추가 해줘야 한다.

만약, 안 하면 객체 생성 시점에서 엑박 뜬다.

 

==> @RequiredArgsConstructor 유무에 따른 outline 차이

 

 

2)  auto increment 설정 

-  설정한 컬럼에 값을 대입하면, 오류

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

 

 

3) null 을 허용한 멤버 변수에 null 값을 초기화 했을 때,

 

- 객체에 다른 멤버 변수가 있을 때,

아래와 같이 바로 값을 초기화하면 에러. 당연히 자바 문법에서는 어떤 값에 null 을 넣었는 지 모르기 때문

 

== > 따로 초기화 해주기

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

@Entity
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@Column(length = 10)//, nullable = false)
	private String name;
	
	@Column(nullable =  true)   
	private int age;
	
	
}
public class RunningTest {

	@Test
	public void step01() {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("dbinfo");

		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();

		Member m1 = new Member();
		Member m2 = new Member();
		
		m1.setName(null);
		m1.setAge(24);

		em.persist(m1);
		em.persist(m2);

		tx.commit();
	}
}

 

 

 

 

3)  int 타입으로 정의된 변수에 @NonNull 을 달았을 때, 주의 가 뜨는 이유

 

int 타입와 같은 Primitive type 멤버 변수는 자바 문법에서 어차피 null 값을 가질 수 없기에,

NonNull, Nollable 할 필요가 없는 것.

 

 

- 그렇다면, JPA 에서 만약 int 타입으로 선언한 멤버 변수 로

생성된 컬럼 값에 null 을 입력하고  싶다면?

 

==  >  객체 생성 후 초기화 시, 해당 컬럼에 아예 값을 넣지 않는다.

          만약, 특정 컬럼에는 값을 넣고 싶다면, set 메소드로 따로 값 초기화 해주기.

	@Test
	public void step01() {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("dbinfo");

		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();

		Member m1 = new Member(); // 값 초기화 안 함.
		
		Member m2 = new Member("유모모", 24);

		em.persist(m1);
		em.persist(m2);

		tx.commit();
	}

 

 

- auto increment를 설정한 pk (null 금지) 이기 때문에, 문법 에러는 뜨지 않았고

  나머지 값들은 int 형 age 는 0,   String 형 name 은 null 값이 들어간다.

 

     => 이때, 값을 넣지 않았음에도 0 값이 들어가는데?!?!  - - 더 찾아보기.

 

 

 

5) null 을 허용하지 않은 멤버 변수 에 값을 초기화하지 않았을 때,

 

*** 위 설명과 같이 NonNull 필드값이 아닌 변수가 있으므로 RequiredArgsConstructor 는 사용할 수 없다.

Hibernate: 
    
    create table Member (
       id integer not null auto_increment,
        age integer,
        name varchar(10) not null,
        primary key (id)
    ) engine=InnoDB

 

- 현재, Member 의 멤버 변수의 id 는 pk 로 null 이 들어가선 안된다.

   그러나, auto increment 설정으로, 객체 생성 시 값을 넣지 않아도 알아서 들어간다.

 

   name 의 경우 nullable = false 설정으로 null 이 불가능 하다.

   age 의 경우는 null 이 가능한 변수이다.

 

이때,  위와 같이 값을 초기화하지 않은 객체를 persist 한 경우, 어떻게 될 것인가?

 

- 콘솔창을 보면, 위와 같이 create 까지 되는데, insert 에서 에러가 발생한다.

 

==> 에러 발생 : null 을 허용하지 않은 name 컬럼에 값이 들어가지 않아서 발생한다.

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value : model.domain.entity.Member.name

 

 

'SW_STUDY > JDBC&JPA' 카테고리의 다른 글

[JDBC] 개요 & Java - mysql 연동 절차 및 문법  (0) 2022.08.10