JPA란?
SQL Mapper
- SQL <- mapping -> object 필드
- SQL문으로 직접 데이터베이스를 조작
- jdbc Template, Mybatis
ORM
- DB 데이터 <- mapping -> Object 필드
- 객체를 통해 간접적으로 데이터베이스의 데이터를 다룸
- 객체와 데이터베이스의 데이터를 자동으로 매핑
- SQL쿼리가 아니라 메서드로 데이터를 조작
- 객체간 관계를 바탕으로 sql을 자동으로 생성
- JPA, Hibemate
ORM은 RDB의 관계를 Object에 반영하는 것이 목적이라면, Mapper는 단순히 필드를 매핑시키는 것이 목적이라는 점에서 지향점의 차이가 있음
JPA
- JPA는 자바 ORM기술에 대한 표준 명세로, JAVA에서 제공하는 API이지 스프링에서 제공하는 것이 아님
- Spring-Data-JPA는 JPA를 쉽게 사용하기 위해 스프링에서 제공하고 있는 프레임워크
- 추상화 정도 (= 손쉽게 기술 사용할 수 있게 많은 api 개발되어 있음)
- Spring-Data-JPA <- Hibernate <- JPA
- Hiberate를 쓰는 것과 Spring Data JPA를 쓰는 것 사이에는 큰 차이가 없음
- 다만 Spring-Data-JPA, Spring Data MongoDB, Spring Data Redis 등 Spring Data의 하위 프로젝트들은 findAll(), save()등을 동일한 인터페이스로 가지고 사용하기 때문에 저장소를 교체하도 기본적인 기능이 변하지 않음
- 이러한 이유에서 Spring Data JPA를 사용하는 것이 좋음
JPA 동작 과정
- 개발자가 JPA를 사용하면 JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신

- insert

- find: 개발자는 JPA에서 데이터 꺼내오는 것이지 DB에서 꺼내는 것이 아님

예시 | insert
Member1.java
package exam1;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name="JpaMember1")
public class Member1
{
@Id
@GeneratedValue
private Long id;
private String username;
@Column(name="create_date")
// @Temporal(TemporalType.TIMESTAMP)
// private Date createDate;
private LocalDate createDate;
protected Member1() {}
public Member1(String username, LocalDate createDate)
{
this.username = username;
this.createDate = createDate;
}
}
- @Entity : 해당 클래스가 JPA의 엔티티임을 의미 = 이 클래스를 @Table 이름으로 만들겠다
- @Id : 엔티티 클래스의 식별자 - DB 테이블의 primary 키
- @GeneratedValue: 자동 생성된 값
- @Column : 매핑할 테이블의 컬럼 이름을 지정, 만약 필드에 어노테이션이 없으면, 필드 이름과 동일한 이름의
테이블 컬럼에 매핑 - @Timestamp : java.util.Date 타입을 매핑 => Java 8에 LocalDateTime 추가되고 (거의) 사용하지 않음
- TemporalType.? 열거 타입
- DATE : java.sql.Date 에 해당
- TIME : java.sql.Time 에 해당
- TIMESTAMP : java.sql.Timestamp 에 해당
- TemporalType.? 열거 타입
- @GeneratedValue(strategy = GenerationType.IDENTITY) : 기본키 생성을 데이터베이스에게 위임하는 방식으로 id값을 따로 할당하지 않아도 데이터베이스가 자동으로 AUTO_INCREMENT를 하여 기본키 생성
- @GeneratedValue(strategy = GenerationType.SEQUNCE)
BasicUse.java
package exam1;
import java.time.LocalDate;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
public class BasicUse
{
public static void main(String[] args)
{istence.createEntityManagerFactory("JpaEx01");
EntityManager entityManager = emf.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction(); //3줄 필수
try {
EntityManagerFactory emf =
Pers
transaction.begin();
Member1 user = new Member1("홍길동1", LocalDate.now());
entityManager.persist(user); // 메모리 안에 영속성으로 insert
transaction.commit(); //실제 db로 insert(db와 영속성 동기화)
} catch (Exception e) {
e.printStackTrace();
transaction.rollback(); //오류나면 rollback
} finally {
entityManager.close();
}
emf.close();
}
}
- persist: 메모리 안에 영속성으로 insert
- commit: 실제 db로 insert
- rollback: 예외처리
JPL을 사용하게 되면 테이블을 직접 관리하지 않아도 된다고 하는 장점은 서비스를 개발할 때 용이하지만, 대규모 SI작업을 할 때는 위험함
예제2 | insert
Member2.java
package exam2;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
@Entity
@Table(name="JpaMember2")
public class Member2
{
@Id
@SequenceGenerator (
name = "mySequence01",
sequenceName = "JpaMember2_SEQ",
initialValue = 1,
allocationSize = 1
)
@GeneratedValue (generator = "mySequence01")
private Long id;
@Access(AccessType.FIELD)
private String username; // 필드를 통해서 데이터 접근
@Access(AccessType.PROPERTY)
private String password; // 프로퍼티(get/set)를 통해서 데이터 접근
@Transient
private long timestamp1; // 영속 대상에서 제외 어노테이션
transient private long timestamp2; // 영속 대상에서 제외 키워드
protected Member2() {}
public Member2(String username, String password)
{
this.username = username;
this.password = password;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}
- @AccessType.FIELD : member변수를 통해서 값에 접근(default)
- @AccessType.PROPERTY : member메소드를 통해서 값에 접근 => getter, setter 만들어줘야함
- @Transient/ teansient: 테이블과 매핑되지 않음
예제3
Member3.java
package exam3;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "JpaMember3")
public class Member3
{
@Id
private String email;
private String name;
@Column(name = "create_date")
private LocalDate createDate;
protected Member3() { }
public Member3(String email, String name, LocalDate createDate)
{
this.email = email;
this.name = name;
this.createDate = createDate;
}
public String getEmail()
{
return email;
}
public String getName()
{
return name;
}
public LocalDate getCreateDate()
{
return createDate;
}
public void changeName(String newName)
{
this.name = newName;
}
}
insert | persist()이용
Test01_insert.java
package exam3;
import java.time.LocalDate;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Test01_Insert
{
public static void main(String[] args)
{
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
Member3 user = new Member3("test@test.com", "홍길동", LocalDate.now());
System.out.println(111); // SQL문 어디서 출력되는지 확인
em.persist(user); // 영속 컨텍스트에 반영
System.out.println(222);
em.getTransaction().commit(); // 실제 sql문 처리
System.out.println(333);
System.out.println("가입 요청을 처리했습니다.");
} catch (Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
select | find()이용
Test02_Select.java
package exam3;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Test02_Select
{
public static void main(String[] args)
{
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
Member3 user = em.find(Member3.class, "test@test.com");//id로 지정된 이메일 컬럼을 통해 검색
System.out.println("["+user+"]");
if (user != null)
{
System.out.println("이름 : " + user.getName());
System.out.printf("생성 : %tY-%<tm-%<td\n", user.getCreateDate());
} else {
System.out.println("존재하지 않습니다.");
}
em.close();
emf.close();
}
}
- find: id로 지정된 이메일 컬럼을 통해 검색
- 멤버변수를 통해 접근하지 않고 getName(), getCreateDate() 등 getter를 통해 값을 가져옴
Update
영속성 개체의 값을 바꿔주기만 하면 됨
Test03_Update.java
package exam3;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Test03_Update
{
public static void main(String[] args)
{
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
Member3 user = em.find(Member3.class, "test@test.com");
if (user == null)
{
System.out.println("존재하지 않습니다.");
em.getTransaction().rollback();
return;
}
user.changeName("전우치"); // 자바 객체를 통해 영속 컨텍스트의 값을 변경
em.getTransaction().commit(); // sql문을 실행해 db에 값의 변경 반영
System.out.println("이름을 변경했습니다.");
} catch(Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- find()로 값을 찾아온 후 user라는 변수에 넣어준후
- user.changeName으로 값을 바꿈
- commit을 하면 db의 값까지 동기화 ( = db 업데이트)
Delete
Test04_Delete.java
package exam3;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Test04_Delete
{
public static void main(String[] args)
{
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
Member3 user = em.find(Member3.class, "test@test.com");
if (user == null) {
System.out.println("존재하지 않습니다.");
em.getTransaction().rollback();
return;
}
em.remove(user);
em.getTransaction().commit();
System.out.println("탈퇴처리 했습니다.");
} catch (Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- 영속성 객체에서 find로 객체를 찾음
- remove()로 영속성 객체에서 지움
- commit으로 동기화하면 db에서도 delete
예제4
Member4.java는 Member3.java와 동일
Test01_Insert.java
package exam4;
import java.time.LocalDate;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
public class Test01_Insert
{
public static void main(String[] args)
{
// hibernate.hbm2ddl.auto의 value : create
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
Member4 user;
user = new Member4("test1@test.com", "이순신", LocalDate.now());
em.persist(user);
user = new Member4("test2@test.com", "강감찬", LocalDate.now());
em.persist(user);
user = new Member4("test3@test.com", "을지문덕", LocalDate.now());
em.persist(user);
user = new Member4("test4@test.com", "계백", LocalDate.now());
em.persist(user);
user = new Member4("test5@test.com", "김유신", LocalDate.now());
em.persist(user);
user = new Member4("test6@test.com", "연개소문", LocalDate.now());
em.persist(user);
user = new Member4("test7@test.com", "양만춘", LocalDate.now());
em.persist(user);
user = new Member4("test8@test.com", "김종서", LocalDate.now());
em.persist(user);
user = new Member4("test9@test.com", "최영", LocalDate.now());
em.persist(user);
em.getTransaction().commit();
System.out.println("가입 요청을 처리했습니다.");
} catch (Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- 데이터 한번에 추가
Test02_TypedQuery.java
package exam4;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.TypedQuery;
public class Test02_TypedQuery
{
public static void main(String[] args)
{
// hibernate.hbm2ddl.auto의 value : none, create
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
TypedQuery<Member4> query =
em.createQuery(
"select m from Member4 m order by m.name",
Member4.class);
List<Member4> result = query.getResultList();//영속성 객체에서 select해서 Member4.class타입으로 가져오겠다.
em.getTransaction().commit();
if (result.isEmpty())
{
System.out.println("사용자가 없습니다.");
}
else
{
result.forEach(user ->
System.out.printf(
"| %s | %s | %tY-%<tm-%<td |\n",
user.getEmail(), user.getName(), user.getCreateDate()));
}
} catch(Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- 세밀한 조정을 위해 sql문과 유사한 TypedQuery문( jpa에서 사용하는 문법) 사용
- 영속성 객체에서 select해서 Member4.class타입으로 가져오겠다
Test03_Parameter.java
- TypedQuery문에 파라미터 넣어서 사용해보기
package exam4;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.TypedQuery;
public class Test03_Parameter
{
public static void main(String[] args)
{
// hibernate.hbm2ddl.auto의 value : none, validate
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
TypedQuery<Member4> query =
em.createQuery(
"select m from Member4 m "
+ " where m.name = :name "
+ " order by m.name",
Member4.class)
.setParameter("name", "양만춘");
List<Member4> result = query.getResultList();
em.getTransaction().commit();
if (result.isEmpty())
{
System.out.println("사용자가 없습니다.");
}
else
{
result.forEach(user ->
System.out.printf(
"| %s | %s | %tY-%<tm-%<td |\n",
user.getEmail(), user.getName(), user.getCreateDate()));
}
} catch(Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- setParameter로 :name에 들어갈 (키값, 검색값) 줌
Test04_ParamLike.java
package exam4;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.TypedQuery;
public class Test04_ParamLike
{
public static void main(String[] args)
{
// hibernate.hbm2ddl.auto의 value : none, validate
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JpaEx01");
EntityManager em = emf.createEntityManager();
try
{
em.getTransaction().begin();
TypedQuery<Member4> query =
em.createQuery(
"select m from Member4 m "
+ " where m.email like :email "
+ " order by m.name",
Member4.class)
.setParameter("email", "%test.com%");
List<Member4> result = query.getResultList();
em.getTransaction().commit();
if (result.isEmpty())
{
System.out.println("사용자가 없습니다.");
}
else
{
result.forEach(user ->
System.out.printf(
"| %s | %s | %tY-%<tm-%<td |\n",
user.getEmail(), user.getName(), user.getCreateDate()));
}
} catch(Exception e) {
em.getTransaction().rollback();
throw e;
}
em.close();
emf.close();
}
}
- =이 아니라 like사용 => test.com으로 들어가있는 것 전부 다 검색
'개발 > Backend' 카테고리의 다른 글
| [Spring Boot] 예제로 배우는 스프링부트 입문 | 배포 (0) | 2024.07.21 |
|---|---|
| [Spring Boot] 예제로 배우는 스프링부트 입문 | Spring Data JPA (0) | 2024.07.21 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | JdbcTemplate (0) | 2024.07.15 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | Form값 검증 (0) | 2024.07.07 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | Web 기초 (0) | 2024.07.06 |