JAVA/ORM

java에서 jpa 사용해보기 _ CRUD (JPA를 사용한 DML처리)

읽히는 블로그 2024. 6. 19. 18:37

▤ 목차

    ✔ 기본 환경설정

    resources 패키지에 

    META-INF와 logback.xml 파일을 생성하고 필요한 값을 설정해 줬다.

    META-INF 패키지 안에 persistences 파일을 생성하고 필요한 값을 설정해 줬다. 

     

    persistences 파일 unit name

     

    //SangpumCRUD 클래스
    
    public class SangpumCRUD {
    	public static void main(String[] args) {
        	EntityManagerFactory emf = Persistence.createEntityManagerFactory("gojpa");
            //Factory : 객체를 싱글톤으로 만들고있다.
    		
    	//EntityManager : thread 단위로 작업 (내부적으로 thread를 사용하고있다.)
    	EntityManager em = emf.createEntityManager();
    	EntityTransaction transaction = em.getTransaction();
         
         /*코드 작성*/
        
        }
    }

     

    싱클톤 패턴이란 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후 호출된 생성자는 최초 생성자가 생성한 객체를 리턴하는 패턴을 말한다.

    즉, 객체의 인스턴스가 오직 1개만 생성되는 패턴을 말한다.

     

     

    🔶EntityManager

    Entity는 실체라는 의미로 데이티 집합을 의미한다. 데이터 베이스에서 영속적으로 저장되고 관리되는 객체를 의미한다.

    데이터베이스 테이블 레코드(행)에 해당한다.

    EntityManager클래스는 위에 언급한 엔티티를 관리하는 역할을 수행하는 클래스이다.

     

    EntityManager 내부에 영속성 컨텍스트 라는 것을 두어 엔티티들을 관리한다.

    영속성이란 전원이 나가도 데이터가 남아있는 비휘발성을 의미한다.

    영속성 컨텍스트를 관리하는 엔티티 매니저는 초기화 및 종료가 되지 않는 한 엔티티를 영구히 저장하는 환경을 말한다.

     

    일반적으로 EntityManager 한 개당 하나의 영속성 컨텍스트를 갖는다. 다만 스프링에서는 공통된 영속성 컨텍스트 하나를 여러 엔티티매니저가 참조한다.

     

    EntitiyManager 만들어진다.

    Entity들을 영속성 컨텍스트에 생성된다.

    Entity Manager가 영속성 컨텍스트를 기반으로 요청(CRUD)을 처리한다.

     

    • 생성하는데 비용이 거의 들지 않는다.
    • 여러 스레드가 동시에 접근하면 동시성 문제가 발생하기 때문에 스레드 간 공유를 하지 않는다.
    • 데이터베이스 연결이 필요한 시점까지 커넥션을 얻지 않는다.

     

    🔶EntityManagerFactory

    java 애플리케이션에서 JPA를 사용하기 위해서는 먼저 엔티티 매니저 팩토리 객체를 생성해야 한다.

    EntityManagerFactory는 EntityManager를 생성하는 역할을 한다.

    엔티티 매니저 팩토리는 이름 그대로 엔티티 매니저를 찍어내는 공장 역할을 하는 인터페이스이다.

     

     

    Entitymanager는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안 된다.

    동시성이란? 유저가 체감하기에는 동시에 수행하는 거처럼 보이지만 사실은 유저가 체감할 수 없는 짧은 시간단위로 작업들을 번갈아가면서 수행하는 것이다. 

     

    • 생성하는데 비용이 크기 때문에 전체에서 한 번만 생성하도록 설계되어 있다.
    • 여러 스레드가 동시 접근해도 안전하다. 즉, 다른 스레드와 공유가 가능하다.

     

     

    🔶EntityTransaction

    EntityManager와 일대일 매핑된다. 엔티티매니저의 작업은 엔티티트랜젝션 클래스에 의해서 유지된다.

    JPA는 자원 로컬 트랜잭션과 자바 트랜잭션 API(JTA) 타입의 두 가지 트랜잭션 타입을 지원한다.

    트랜잭션 타입은 persistence.xml 파일의 tancaction-type 속성값을 설정하면 된다. 

     

     

    🔶Persistence (영속) 클래스

    클래스는 JPA에서 엔티티 매니저 팩토리를 생성하는 가장 간단한 방법을 제공한다.

    엔티티매니저팩토리 인스턴스를 생성하는 정적 메서드를 가지고 있다.

     

    xml 설정파일의 Persistence Unit을 통해 엔티티 매니저 팩토리를 생성한다.

    JPA의 Persistence 클래스가 META-INF/persistence.xml 설정 파일을 읽어서 EntityManagerFactory라는 클래스를 생성한다. 

     

     

     

     


     

     

    ✔ 자료 읽기 select

    ⌨ 전체 자료 읽기

    try {
    			System.out.println("전체 자료 읽기 1 ");
    			CriteriaBuilder cb = em.getCriteriaBuilder();
    			
    			CriteriaQuery<SangpumTable> query = cb.createQuery(SangpumTable.class);
    			
    			//조회의 시작점을 의미하는 root 객체 생성
    			Root<SangpumTable> root = query.from(SangpumTable.class); //from절
    			query.select(root); //select절
    			List<SangpumTable> resultList = em.createQuery(query).getResultList();
    			
    			for(SangpumTable st : resultList) {
    				System.out.println(st.getCode() + " "+ st.getSang() + " " + st.getSu() +  " " + st.getDan());
    			}
    			
    			System.out.println("전체 자료 읽기 2");
    			//TypedQuery을 이용해 JPQL 사용
    //			TypedQuery<SangpumTable> queryql = em.createQuery("select s from SangpumTable s", SangpumTable.class); //SangpumTable 엔티티 테이블이다.
    //			List<SangpumTable> list = queryql.getResultList();
    			//위의 두줄을 한줄로
    			List<SangpumTable> list = em.createQuery("select s from SangpumTable s", SangpumTable.class).getResultList();
    			
    			
    			for(SangpumTable st : list) {
    				System.out.println(st.getCode() + " "+ st.getSang() + " " + st.getSu() +  " " + st.getDan());
    			}
    			
    		} catch (Exception e) {
    			System.out.println("err: "+e);
    		}finally {
    			em.close();
    			emf.close(); // 필수
    		}
    	}

     

     

    ✒️ 사용 클래스 및 메서드

    ✏️CriteriaBuilder()

    Criteria는 JPQL의 작성을 도와주는 빌더 클래스이다.

    문자열로 JPQL을 작성하면 런타임이 되어야 문법 오루를 알 수 있지만 cRITERIA는 자바 코드 기반이기 때문에 안전하게 JPQL을 작성할 수 있다.

     

    Criteria

    • 문법 오류를 컴파일 단계에서 확인이 가능하다.
    • 문자 기반의 JPQL보다 동적 쿼리를 안전하게 생성한다.
    • 코드가 복잡하고 장황해서 직관적이지 않아 가독성이 떨어진다.

    Criteria query는 빌더를 필요로 한다.

    이때 엔티티 매니저나 엔티티 매니저팩토리로 생성한다.

     

     

    💻 일부 자료 읽기

    try{
    	System.out.println("\n== 부분 자료 읽기 1==");
    	int findId = 1; // String으로 읽어도 상관없다. String findId = 1; find()메서드는 pk 칼럼이 대상이다.
    	SangpumTable sangtab = em.find(SangpumTable.class, findId); //SangpumTable은 논리적 테이블 >물리적 테이블과 연결되어있다.
    	if(sangtab == null) {
    		System.out.println("자료 없음");
    	}else {
    		System.out.printf("%s %s %s %s\n",sangtab.getCode(),sangtab.getSang(),sangtab.getSu(),sangtab.getDan());
    	}
    			
    	System.out.println("\n== 부분 자료 읽기 2==");
    	TypedQuery<SangpumTable> typedQuery = em.createQuery(query.where(cb.equal(root.get("sang"),"장갑")));
    	List<SangpumTable> list2 = typedQuery.getResultList();
    	for(SangpumTable st : list2) {
    		System.out.printf("%s %s %s %s\n",sangtab.getCode(),sangtab.getSang(),sangtab.getSu(),sangtab.getDan());
    	}			
    	
    			
    	} catch (Exception e) {
    		System.out.println("err: "+e);
    	}finally {
    		em.close();
    		emf.close(); // 필수
    	}

     


    ✔ 자료 추가

    💻 코드로 보기

    try {
    	transaction.begin(); // auto commit false로 전환
    	SangpumTable sangtab = new SangpumTable(5,"도시락",3,6000); //생성자타고 들어간다.
    	//pk가 있는 값이면 아래와 같은 err가 나타난다.
    	//ins err: jakarta.persistence.RollbackException: Error while committing the transaction
    	em.persist(sangtab);
    	transaction.commit();			
    } catch (Exception e) {
    	System.out.println("ins err: "+e);
    	transaction.rollback();
    	return;
    	
    }

     

    👏 중요

    transaction이 있다.

     

     

     


     

     

     

     

    ✔ 자료 수정

    💻 코드로 보기

    try {
    	transaction.begin();
    	SangpumTable sangtab = em.find(SangpumTable.class,"5");
    	if(sangtab == null) {
    		System.out.println("해당자료없음");
    	}else {
    //		String newName = "마스크";
    //		sangtab.setSang(newName);
    		sangtab.setSang("마스크");
    		transaction.commit();
    	}
    		
    	} catch (Exception e) {
    		System.out.println("up err: "+e);
    		transaction.rollback();
    		return;
    	}

     

    👏 중요

    transaction이 있다.

     

     

     

     


    ✔자료 삭제

    💻 코드로 보기

    try {
    	transaction.begin(); //transaction 시작
    	int findCode = 5;
    	SangpumTable sangtab = em.find(SangpumTable.class, findCode);
    	if(sangtab == null) {
    		System.out.println("해당자료없음");
    		transaction.rollback();
    	}else {
    		em.remove(sangtab);
    		System.out.printf("\n%s자료 삭제됨 \n",findCode);
    		transaction.commit();
    	}
    		
    	} catch (Exception e) {
    		System.out.println("dl err: "+e);
    		transaction.rollback();
    		return;
    	}

    👏 중요

    transaction이 있다.

     

     

    😊정리

    순수 자바에서 jpa는 잘 사용하지 않는다.

    spring으로 jpa를 사용하면 위보다 설정 코드가 많이 줄어들기 때문이다.

    jpa는 sql을 추상화한 jpql이라는 객체 지향 쿼리 언어를 제공한다.

    JPQL의 장점은 sql을 추상화했기 때문에 sql에 의존하지 않아도 된다는 장점이 있다.

    추상화이기에 결국 sql로 변환한다.

    jpa에서 sql을 사용하기 위해서는 맞는 문법을 따로 공부해야 한다.

    JPQL 문법은 따로 정리해 보겠다.