JPA

AI·2025년 10월 20일

JPA

Java Persistence API
https://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html
Object Relational Mapping - 자바 객체 관계형 데이터 베이스 테이블 매핑
구현체 : 하이버네이트(Hibernate)
sql 작성 안하려는 노력(등록, 수정, 삭제는 자동화, select는 부분 자동화)

  • 초급자가 sql을 잘 모르고 넘어가는 경우가 있어 sql을 완전히 숙지하는 것을 추천한다고 함
    => 규모가 작은, 생명 주기가 짧은 프로젝트에 사용 -> 20~30%만 sql 작성하고 나머지 자동화, 단순함
    => 1차 캐시 => 영속화 컨텍스트(Persistence context) - 트랜잭션 단위

하이버네이트

  1. xml 방식
    resource에 생성
    persistence-unit 여러개 생성 가능
import jakarta.persistence.Entity; // javax -> jakarta
import jakarta.persistence.Id;

@Entity
public class Product {
    @Id
package entity;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

//spring을 제외한 jpa 사용
public class Test {
    public static void main(String[] args){
        // EntityManagerFactory -> EntityManager
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu"); // unit name
        EntityManager em = emf.createEntityManager();
        
        em.getTransaction().begin(); // 1차 캐시 준비
        
        // 작업 수행
        
        em.getTransaction().commit();
        
        em.close();
    }
}
        // 1건
        {
            Product p = new Product();
            p.setId(1);
            p.setName("Book");

            em.persist(p); // 이 시점에 insert X - commit때 insert
        }
        // 여러 건
        {
            Product p2 = new Product();
            p2.setId(2);
            p2.setName("Phone");

            Product p3 = new Product();
            p3.setId(3);
            p3.setName("Car");

            // persis 순서대로 inser X
            // 영속화 context가 flush() (commint()이 flush() 호출) 되는 시점에 결정(순서는 알 수 없지만 id 순으로 되는 거 같음)
            em.persist(p3);
            em.persist(p2);
        }
public class MyPersistenceUnitInfo implements PersistenceUnitInfo

HikariCP 추가

    @Override
    public String getPersistenceUnitName() {
        return "my-pu"; // 이름 맞게 설정
    }

    @Override
    public String getPersistenceProviderClassName() {
        return "org.hibernate.jpa.HibernatePersistenceProvider";
    }

    @Override
    public PersistenceUnitTransactionType getTransactionType() {
        return PersistenceUnitTransactionType.RESOURCE_LOCAL;
    }

    @Override
    public DataSource getJtaDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("db 주소");
        dataSource.setUsername("이름");
        dataSource.setPassword("비번");
        return dataSource;
    }
    @Override
    public List<String> getManagedClassNames() {
        return List.of("entity.Product");
    }
        EntityManagerFactory emf= new HibernatePersistenceProvider()
                .createContainerEntityManagerFactory(new MyPersistenceUnitInfo(), new HashMap<>());
        EntityManager em = emf.createEntityManager();
        
        em.getTransaction().begin();
        // TODO
        em.getTransaction().commit();
        em.close();
        for(int i=1;i<=3;i++){
            Product p = new Product();
            p.setId(i);
            p.setName("Phone"+i);
            em.persist(p);
        }
        Product p = new Product();
        p.setId(4);
        p.setName("Watch");

        em.persist(p); // p객체는 영속화 context에 담긴 상태 - entitymanager가 관리

        p.setName("Glasses");

commit할때의 상태로 저장됨

@Entity
@Table(name = "emp")
public class Employee {
    @Id
    @Column(name = "emp_id")

table이랑 column명 달라도 적용 가능

  • 없는 값은 null 출력
  • 존재하는 id를 넣으려고 하면 에러 발생

find

        // find
        // table data -> 객체화 & 영속화
        {
            Employee e = em.find(Employee.class, 1);
            System.out.println(e);

            Employee e2 = em.find(Employee.class, 2);
            System.out.println(e2); // 없는 값은 null 출력
        }

merge

        // merge
        // 객체가 테이블에 없으면 insert, 있는 객체면 update
        {
            // 없는 데이터
            Employee e = new Employee();
            e.setId(2);
            e.setName("lee");
            e.setAddress("gangju");

            em.merge(e);

            // 있는 데이터
            Employee e2 = new Employee();
            e2.setId(1);
            e2.setName("hong");
            e2.setAddress("busan");

            em.merge(e2);
        }

detach

        // detach
        // 영속화 context에서 분리(em이 관리 x)
        {
            Employee e = em.find(Employee.class, 2);
            System.out.println(e);

            em.detach(e);

            e.setAddress("jeju");
            System.out.println(e); // 출력은 jeju로 되지만 실제 db에는 detach 전의 값을 가짐
        }

remove

        // remove
        {
            Employee e = em.find(Employee.class, 2);
            System.out.println(e);
            em.remove(e);

            Employee e2 = new Employee();
            e2.setId(1);
            em.remove(e2); // error(IllegalArgumentException: 
            // Removing a detached instance entity.Employee#1)
        }
        Map<String, String > props = new HashMap<>();
        props.put("hibernate.hbm2ddl.auto","update"); // create(drop&create), update(없으면 create, 변하면 alter)
        props.put("hibernate.show_sql","true"); // 수행되는 sql 출력

        EntityManagerFactory emf= new HibernatePersistenceProvider()
                .createContainerEntityManagerFactory(new MyPersistenceUnitInfo(), props);
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

        // ddl option update(현재 엔티티와 동일한 테이블 존재) => 아무일 x
        // 테이블 x => 테이블 생성
        // 컬럼이 다름 => 컬럼 추가/삭제

        em.getTransaction().commit();
        em.close();
    }

jpql

import entity.Book;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.TypedQuery;

import java.util.List;

// select
// em.commit() 사용 x
// jpql - sql과 유사한 거
public class Test {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu");
        EntityManager em = emf.createEntityManager();

        //typed query
        {
            String jpql = "select b from Book b"; // table이 아니라 entity
            // Hibernate: select b1_0.bookid,b1_0.bookname,b1_0.price,b1_0.publisher from Book b1_0
            TypedQuery<Book> query = em.createQuery(jpql, Book.class);
            List<Book> bookList = query.getResultList();
            for(Book book : bookList){
                System.out.println(book);
            }
        }
        
        em.close();
    }
}

typed query + parameter

        //typed query + parameter
        {
            String jpql = "select b from Book b where b.price > ?1";
            TypedQuery<Book> query = em.createQuery(jpql, Book.class);
            query.setParameter(1,15000);
            List<Book> bookList = query.getResultList();
            for(Book book : bookList){
                System.out.println(book);
            }
        }
        {
            String jpql = "select b from Book b where b.price > :price";
            TypedQuery<Book> query = em.createQuery(jpql, Book.class);
            query.setParameter("price",15000);
            List<Book> bookList = query.getResultList();
            for(Book book : bookList){
                System.out.println(book);
            }
        }

0개의 댓글