영속성 컨텍스트 (EntityManager)
  • 엔티티를 영구 저장하는 환경
  • EntityManager.persist(entity);  

 

먼저 persist()의 역할을 알아보면 EntityManager 를 사용해서 엔티티를 영속성 컨텍스트에 저장하는것! ( DB에 저장 X)

 

 

엔티티의 생명주기

비영속 : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태

영속 : 영속성 컨텍스트에서 관리되는 상태

준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태

 

1. 비영속

member 객체를 생성한 상태 (jpa도 아니고 DB에도 들어가지 않은 아무것도 아닌 상태)

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

 

2. 영속

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

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

//객체를 저장한 상태(영속)
em.persist(member);

em.persist(member); 는 객체를 영속성 컨텍스트에 저장은 했으나 DB에 저장된 상태는 아니다.

영속상태가 되었다고 DB에 저장된게 아니라

트랜잭션을 커밋하는 시점에 영속성 컨텍스트에 있는 객체가 DB에 쿼리가 날라간다. 

(또한 em.find를 처럼 jpa를 통해 조회했을때도 영속성 컨텍스트에 없으면 저장은 되어 영속성 상태는 된다.)

 

 

 

 

 

3. 준영속 그리고 삭제

 

  • 준영속 상태란?

영속상태의 엔티티가 영속성 컨텍스트에서 분리되는 것

영속성 컨텍스트가 제공하는 기능(더티체킹..)을 사용못한다.

 

  • 준영속 상태로 만드는 방법
  • em.detach(member) : 영속성 컨텍스트 안에서 member 엔티티를 분리(삭제)해서 아무것도 아닌 상태(준영속 상태)로 만드는 것
  • em.clear() : 영속성 컨텍스트 전체를 완전히 초기화 
  • em.close() : 영속성 컨텍스트를 종료 (데이터를 변경해도 안됨)

 

  • 왜 준영속 상태로 만드는가? jpa가 관리할 필요가 없는 엔티티를 준영속 상태로 만든다

 

삭제

  • em.remove(member) 는 객체를 삭제한 상태 (DB에서 삭제)

 

 


 

영속성 컨텍스트의 이점
  • 1차 캐시
  • 동일성(identity) 보장
  • 트랜잭션을 지원하는 쓰기 지연
  • 변경 감지 (더티 체킹)
  • 지연 로딩 

 

 

1. 1차 캐시

 

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

//객체를 저장한 상태(영속)
em.persist(member);

 

키가 'member1' 이고 em.persist(member) 를 통해 저장한 객체가 Entity에 들어감

 

 

1차 캐시에서 조회할때 DB에서 값을 가져오는게 아니라 먼저 1차 캐시에서 member 엔티티를 가져온다. 

//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

//1차 캐시에 저장됨
em.persist(member);

//1차 캐시에 조회
Member findMember = em.find(Member.class, "member1");

 

 

만약 findMember2 엔티티가 DB에는 있고 1차 캐시에는 없다면? 

Member findMember2 = em.find(Member.class, "member2");

 

1. 1차 캐시에 먼저 조회를 하고 없다면

2. DB에 findMember2 찾아 조회한다

3. 1차 캐시에 저장시키고

4. member2 를 반환한다. 

 

이제 findMember2 를 또 조회를 한다면 DB가 아니라 1차 캐시에서 들고온다 

 

 

 

2. 동일성 보장 (1차 캐시에서 들고왔기 때문에 동일함)

 

* 단, 같은 트랜잭션 안에서 비교해야 동일하다

 

 

 

3. 트랜잭션을 지원하는 쓰기 지연

EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //DB 트랜잭션 시작

em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 DB에 보내지 않는다

tx.commit(); //트랜잭션 커밋하는 순간 INSERT SQL을 DB에 보낸다.

 

em.persist() 하는 시점에서 영속성 컨텍스트에 memberA,B가 담기고 

쓰기지연 SQL 저장소에 memberA, memberB의 INSERT 문(쿼리문)이 저장이 된다.

 

 

그 다음 tx.commit();

커밋하는 시점에서 쓰기지연 SQL 저장소가 DB에 flush 해서 쿼리문이 반영이 된다. 

 

아래의 flush 는 쓰기 지연 SQL 저장소의 쿼리(등록,수정,삭제 쿼리)를 DB에 전송

 

왜 em.persist 할때 쿼리문이 안 날라갈까? 

모았다가 DB에 저장하기 위해! 

 

 

flush
: 영속성 컨텍스트의 변경내용을 DB에 날려주는 것

 

영속성 컨텍스트를 플러시 하는 방법(2가지)
1. em.flush() - 직접 호출
2. 트랜잭션 커밋 - 플러시 자동 호출
flush 의 역할 
1. 영속성 컨텍스트를 비우지 않는다
2. 영속성 컨텍스트의 변경내용을 DB에 동기화 역할
3. 트랜잭션이라는 작업 단위가 중요하다 (커밋 직전에만 동기화하면 된다. )

 

 

 

4. 변경 감지 (더티 체킹)

EntityManagerFactory emf = Persistence.createEntityManagerFactory(
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //DB 트랜잭션 시작

try{
	//영속성 컨텍스트 조회
    Member member = em.find(Member.class, "memberA");
    //영속성 컨텍스트 수정
    member.setName("회원1");

	//em.persist(member); 
	//JPA는 변경감지 하여 업데이트 쿼리문을 날린다
	
    //커밋
    tx.commit();

}catch {
	tx.rollback();
}finally {
	em.close;
}

 

em.update(member) 을 할 필요가 없음.

커밋하는 시점에 1차 캐시와 스냅샷을 비교한다

1차캐시에는 '엔티티(memberA )'와 영속성 컨텍스트에 들어온 최초 상태인 '스냅샷'이 있는데

이때 memberA 를 변경을 하고 커밋하는 시점에 JPA가 엔티티와 스냅샷을 비교한다. 

memberA 가 바껴있으면 업데이트 쿼리를 쓰기 지연 SQL 저장소에 만들고

쓰기 지연 SQL 저장소에 있는 업데이트 쿼리를 DB에 반영하고 커밋한다

 

 

 

 

 엔티티 삭제

 

 

 

반응형
LIST
JPA 구동 방식 

 

JPA 구동방식을 설명하자면

먼저 Persistence 클래스에서 시작해서 설정 정보를 조회하고 EntityManagerFactory 클래스를 생성한다

마지막으로 EntityManagerFactory 클래스에서 나오는 EntityManager 들을 생성한다.

 

 

 

실제 코드)

메인 클래스에서 EntityManagerFactory 생성 

그렇게 되면 DB와 연결이 가능해진다.

 

* [persistence.xml] 에서 <persistence-unit name="hello"> 이름을 넣는다

 

 

 

EntityManager 생성

DB에 조회하고 저장하는 실제 코드는 EntityManager 생성 후 작성해야한다.

public class JpaMain {
	public static void main(String[] args) {
       
       //EntityManagerFactory 는 애플리케이션 로딩시점에 딱 하나만 만들어놔야한다
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        //'상품을 장바구니에 담기'같은 DB커넥션을 얻고 쿼리를 줘서 종료되는 일련의 과정의 단위를 할때마다 EntityManager를 만들어줘야함
        EntityManager em = emf.createEntityManager();
        
        //실제 code 작성위치 (DB데이터 조회,저장...)
        
        em.close();
        emf.close();
        
        
}

 

 

 

 

@Entity
public class Member {

	//PK 설정(@Id 어노테이션)
	@Id 
	private Long id;
	private String name;
	
    //getter, setter
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

@Entity 어노테이션을 꼭 써야하는 이유는 JPA가 처음 실행할때 인식을 하게 만든다.

 

public class JpaMain {
	public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        EntityManager em = emf.createEntityManager();
        
        //JPA는 트랜잭션 안에서 작업해야한다 
        //쉽게 말해 DB 커넥션을 받아놓는다
        EntityTransaction tx = em.getTransaction();
        tx.begin(); //DB 트랜잭션 시작
        
        //member 객체 생성
        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");
        
        //저장
        em.persist(member);
        //커밋
        tx.commit();
        
        em.close();
        emf.close();
        
        
}​

객체를 생성하고 setID, setName 을 저장한다고 저장이 안된다 

왜냐하면 jpa는 트랜잭션 안에서 작업을 해야하기 때문이다 

 

트랜잭션을 실행하여 값을 저장하고 커밋을 하면 DB에 값이 저장된다.

EntityTransaction tx = em.getTransaction();
tx.begin();
//실제코드~~
tx.commit();

 

여기까지가 JPA의 정석으로 쓰는 코드다.

실제로는 스프링이 해결해줘서 굳이 안써도 되고 

public class JpaMain {
	public static void main(String[] args) {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
		
		EntityManager em = emf.createEntityManager();
		
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		
        
		try {
			Member findMember = em.find(Member.class, 1L); //(클래스 이름, PK)
			//수정
			findMember.setName("HelloJPA");
			
            //DB에 저장안해도 된다. 
            //em.persist(findMember);
            
			tx.commit();
		} catch (Exception e) {
			tx.rollback();
		} finally {
			em.close();
        }
		emf.close();
	}
}

 

em.persist(findMember); 를 안 쓰는 이유

원래는 em.persist 를 해서 DB에 저장을 시켰으나

JPA가 트랜잭션 커밋하는 시점에서 변경된걸 모두 확인 하고 알아서 업데이트 쿼리를 날리기 때문에 쓸 필요가 없다. 

 

 

다시 말해, EntityManagerFactory 는 DB 당 하나만 생성되고

EntityManager 는 고객의 요청이 올때마다 생성하고 다시 버려야한다 (em.close)

그렇기 때문에 여러 쓰레드간에 공유하면 안된다

JPA의 모든 데이터 변경은 트랜잭션 안에서 실행한다 (사실 내부적으로 알아서 처리를 함)

 

 

 

 

반응형
LIST

 

JPA 등장배경

JDBC > MyBatis, JDBCTemplate > JPA 순서

 

과거에는 순수 JDBC를 사용하여 객체를 DB에 저장하려면 JDBC API와 SQL를 직접 입력해야 했다

지금은 JPA를 사용하면 SQL을 작성할 필요가 없어진다.

JPA는 SQL 자동화, 수십 줄의 코드를 한 두줄로 줄일 수 있다.

 

여기서 객체와 데이터를 매핑하는 게 중요하다.

기본키와 외래키 매핑, 1:N, N:1, 1:1 , N:M

 

 

JPA 내부동작 방식과 JPA가 어떤 SQL을 만드는지 언제 실행하는지를 이해해 보자

 

객체를 관계형 DB에 관리한다.

어떻게? 수많은 SQL 쿼리로! 

 

  • SQL 중심개발의 문제점

객체 하나를 DB에 CRUD(조회, 수정, 삭제..)를 하려면 수많은 SQL을 작성해야해서 무한반복이 되기 때문에

SQL 중심적인 개발의 문제점이다

예를들어 객체 필드를 추가하면 쿼리문을 모두 수정해야하기 때문에 SQL에 의존적인 개발을 피하기 어렵다.

(JPA는 SQL을 처리해줌)

 

 

패러다임 불일치란?
객체와 DB는 목적이 다르다

객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.

객체를 영구 보관하는 다양한 저장소들이 있다 > RDB, NoSQL, File, OODB

그 중 8~90% 는 현실적인 대안으로 관계형 데이터베이스에 저장(RDB)한다. 

 

먼저 객체를 관계형 데이터베이스에 저장하려면 어떤 순서대로?

객체 > SQL 변환 > RDB에 SQL에 전달한다 누가?  개발자가! 

즉 개발자는 SQL매퍼 일을 한다.

 

 

 

 

상속

 

다시 돌아가서 

데이터를 DB에 저장을 할 때

관계형 데이터베이스는 객체의 상속관계를 저장할 수 있을까? NO!!

부모 테이블 - 자식 테이블을 나눠 만들어서 데이터를 분리하여 필요할 땐 조인해서 들고올 수 있다

이것을 '슈퍼타입, 서브타입'이라고 한다.

 

Album 테이블을 들고오고 싶으면 ALBUM 테이블과 ITEM 테이블을 조인해서 같이 들고와서.. 각 객체 생성하고 ....

 = 조인쿼리 때문에 복잡해짐

이것을 모두 개발자가 해야하는 문제가 생겨버림

 

 

만약 자바 컬렉션에 저장한다면? 

list.add(album);

 

또는 자바 컬렉션에서 조회한다면?

Album album = list.get(albumId);

 

자바 컬렉션에 저장하는 이유는 아래에서 자세히 설명.

 

 

연관관계

객체는 참조를 사용  테이블은 외래키를 사용
member.getTeam(); JOIN ON M.TEAM_ID = T.TEAM_ID

 

member 객체와 team 객체를 데이터에 저장할때 테이블에 맞춰서 모델링을 해야한다. 

class Member {
	String id;
	Long teamId; //TEAM_ID FK 컬럼사용
	String username;
}

class Team {
	Long id; //TEAM_ID PK 컬럼사용
	String name;
}

 

 

이것보다 객체답게 모델링하는 방법은 참조의 연관관계를 맺는다.

class Member {
	String id;
	Team team; // 연관관계
	String username;
}

위와 같이 insert into Member (MEMBER_ID, TEAM_ID, USERNAME) 쿼리문을 날릴때

member 클래스에는 team에 대한 참조만 있고 teamId는 없기때문에

우선 멤버 객체에서 team을 조회하고 teamId를 가져온다.

member.getTeam().getId();

 

 

 

위처럼 member와 team을 DB에 저장하는게 아니라 자바 컬렉션에 관리를 한다면?

연관관계만 설정해두고 member만 추가를 하면 연관된 team이 컬렉션에 들어가게된다. 

list.add(member);
Member member = list.get(memberId);
Team team = member.getTeam(); 

 

**자바컬렉션에서 조회하여 두개의 인스턴스를 생성하여 값을 넣으면 비교했을때 값이 같다. 

String memberId = "123";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
 
 member1 == member2; //같음

 

그치만 객체답게 모델링할수록 매핑작업이 늘어난다...

객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수는 없을까??

 

그 문제를 해결하는게 바로 JPA 기술이다.

 

 

JPA 

Java Persistence API 

자바진영의 ORM 기술표준이다

 

ORM

Object-relational mapping 객체 관계 매핑 (객체와 관계형 DB를 매핑)

객체는 객체대로 설계

관계형 데이터베이스는 관계형 데이터베이스대로 설계

ORM 프레임워크가 중간에서 매핑

java 같은 대중적인 언어에는 ORM 기술이 존재

 

 

 

JPA는 애플리케이션과 JDBC 사이에서 동작한다

원래는 개발자가 JDBC API를 썼다면 이제는 JPA가 대신 쓴다

 

 

JPA 동작 (저장)

멤버 객체를 저장할때 JPA에 저장해달라고 던져주면 JPA가 회원 객체를 분석하여 INSERT SQL을 생성하고

JDBC API를 사용하여 DB에게 INSERT 쿼리문을 날려준다 중요한건 패러다임 불일치 해결

 

JPA 동작 (조회)

조회할때 JPA가 회원 객체를 분석하여 SELECT SQL 생성 JDBC API를 사용하여 ResultSet매핑,  패러다임 불일치 해결

Entity 오브젝트를 만들어서 결과를 반환해준다.

 

 

JPA는 표준명세이며 표준 인터페이스의 모음이다

표준 인터페이스를 구현한 대표적인 구현체는 하이버네이터이다 (90퍼이상 사용)

 

JPA 와 CRUD

저장 jpa.persist(member)

조회 Member member = jpa.find(memberId)

수정 member.setName("변경할 이름")

삭제 jpa.remove(member)

 

 

 

JPA 장점

- SQL 중심적인 개발에서 객체 중심으로 개발

- 생산성

저장 : jpa.persist(member)
조회 : Member member = jpa.find(memberId)
수정 : member.setName("변경할 이름")
삭제 : jpa.remove(member)

 

 

- 유지보수

  • 기존 : 필드 변경시 모든 SQL 수정을 해야함
public class Member {
	private String memberId;
	private String name;	
	private String tel; // 필드 추가
}
INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES
SELECT MEMBER_ID, NAME, TEL FROM MEMBER M
UPDATE MEMBER SET... TEL = ?
  • JPA : 필드만 추가하면 된다. SQL은 JPA가 처리해줌

 

 

- 패러다임 불일치 해결

  • JPA 와 상속
  • JPA 와 연관관계
  • JPA 와  객체 그래프 탐색
  • JPA 와 비교하기

 

 

- 성능

  • 1차 캐시와 동일성 보장 (같은 트랜잭션 안에서는 같은 엔티티를 반환)

m1 > 처음에는 sq쿼리문으로 조회를 하고 (jpa가 값을 들고 있음 )

m2 > 그 다음에는 캐시에 저장된 객체를 반환 

 

*SQL은 1번만 실행하며 같은 트랜잭션안에서만 가능하다.

String memberId = "100";
Member m1 = jpa.find(Member.class, memberId); //SQL 쿼리
Member m2 = jpa.find(Member.class, memberId); //캐시(메모리상)에서 반환

printIn(m1 == m2)  // true

 

  • 네트워크 통신비용을 줄일 수 있다.
transaction.begin(); // 트랜잭션 시작

//아직까지 INSERT SQL 을 DB에 안보냄
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//커밋하자마자 DB의 INSERT SQL을 모아서 보낸다
transaction.commit(); // 트랜잭션 커밋

 

 

  • 지연로딩 (Lazy loading)

: 객체가 실제 사용될때 로딩

멤버를 조회할때 항상 팀도 조회가 된다면? 멤버를 조회할때 팀을 한번에 조인해서 가져오는게 네트워크 통신비용이 감소

또는 멤버만 조회를 하고싶고 연관된 팀을 안가져오고 싶을때

 

반대로 멤버와 팀을 자주 사용한다면 '즉시 로딩'이다.

 

 

- 데이터 접근 추상화와 벤더 독립성

- 표준

 

 

 

 

 

반응형
LIST

메이븐 프로젝트 설정

 

웹이 필요하면 webapp 선택, 자바 결과값만 간단하게 확인할거면 quickstart 선택

나는 quickstart 선택

 

- quickstart 

quickstart

- webapp

webapp

 

 

메이븐 그룹 Id 와 Artifact Id , 버전 지정하기

* Artifact Id : 프로젝트 파일 명

 

 


아래의 오류가 난다면? Could not write metadata for '/'.

> 이클립스 workspace 폴더안에 .metadata 폴더를 삭제를 한다. 

Could not write metadata for '/'.

 

 


 

 

pom.xml 에서 JPA 하이버네이트와 H2 데이터베이스 라이브러리 넣기

  • JPA 하이버네이트 추가 - 인터페이스 JPA 구현체를 갖고있는 hibernate
  • H2 데이터베이스 추가 - DB접근할 수 있는 드라이버 

라이브러리 추가할 때 버전 중요하다

<!-- JPA 하이버네이트 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.3.10.Final</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.214</version>
</dependency>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
 <modelVersion>4.0.0</modelVersion>

  <groupId>jpa-basic</groupId>
  <artifactId>ex1-hello-jpa</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <name>ex1-hello-jpa</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
	<!-- JPA 하이버네이트 -->
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-entitymanager</artifactId>
		<version>5.3.10.Final</version>
	</dependency>
	<!-- H2 데이터베이스 -->
	<dependency>
		<groupId>com.h2database</groupId>
		<artifactId>h2</artifactId>
		<version>2.1.214</version>
	</dependency>
	
  </dependencies>

	
</project>

 

 

 

먼저 Hibernate 버전 

<!-- JPA 하이버네이트 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.3.10.Final</version>
</dependency>

하이버네이트 5.3.10 버전을 쓰는 이유는 jpa 혼자 쓰면 버전은 크게 중요하지 않는데 스프링을 엮어서 실핼할 때 hibernate 버전도 맞춰서 사용하면된다. 

 

 

스프링을 사용한다면? 내가 사용하는 스프링 버전에서 사용하는 하이버네이트 버전을 확인해보자 

 

 

스프링부트에서 하이버네이트 버전 확인하는 법

스프링부트 Projects - Spring Boot 들어가서 내가 사용할 버전의 Reference Doc. 들어가보면 

 

hibernate-entitymanager 을 보면 스프링부트에서 사용할 하이버네이트 버전이 나온다 (예시사진이라 버전이 안맞음)

버전에 맞춰 하이버네이트를 사용하면 된다

 

 

그리고 javax.persistence 에서는 jpa인터페이스가 모두 들어가있다.

hibernate는 jpa구현체를 갖고있다

인터페이스= jpa

인터페이스 구현체로 hibernate 라이브러리를 선택했는데 persistence에 들어가면 앞으로 사용할 jpa인터페이스가 모두 들어가있다는 것.

 

 

 

두번째로 H2 라이브러리 버전 

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.214</version>
</dependency>

h2 다운받을때 <version>2.1.214</version> 버전 맞춰서 다운받는걸 권장한다.

 

 

 

 

 

이제 JPA 설정해보자

 

JPA 설정법

1. src / main / java 에 META-INF 폴더 생성

 

2. META-INF 폴더안에 persistence.xml 파일을 만들어서 프로젝트에 넣는다.

 

persistence.xml 안에 코드 복붙하기

<persistence version="2.2"
	xmlns="http://xmlns.jcp.org/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
	<persistence-unit name="hello">
		<properties>
			<!-- 필수 속성 -->
			<property name="javax.persistence.jdbc.driver"
				value="org.h2.Driver" />
			<property name="javax.persistence.jdbc.user" value="sa" />
			<property name="javax.persistence.jdbc.password" value="" />
			<property name="javax.persistence.jdbc.url"
				value="jdbc:h2:tcp://localhost/~/test" />
			<property name="hibernate.dialect"
				value="org.hibernate.dialect.H2Dialect" />

			<!-- 옵션 -->
			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />
			<property name="hibernate.use_sql_comments" value="true" />
			<!--<property name="hibernate.hbm2ddl.auto" value="create" /> -->
		</properties>
	</persistence-unit>
</persistence>

 

 

<property name="hibernate.hbm2ddl.auto" value="create" /> 에  주석처리를 해제해줘야 DB에 쿼리문이 날려서 값이 저장이됨.

 

 

JpaMain 클래스를 만들어서 Member 객체 생성하고 값 넣어보기

public class JpaMain {

	public static void main(String[] args) {
		//애플리케이션 로딩시점에 딱 하나만 만들어놔야한다
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
		
		//상품을 장바구니에 담기같은 db 커넥션을 얻어서 쿼리를 줘서 종료되는 일련의 과정의 단위를 할때마다 EntityManager를 만들어줘야함
		EntityManager em = emf.createEntityManager();
		
		//jpa는 트랜잭션 안에서 작업해야한다 
		//쉽게 말해 DB 커넥션을 받아놓는다
		EntityTransaction tx = em.getTransaction();
		tx.begin(); //DB 트랜잭션 시작
		
		Member member = new Member();
		member.setId(1L);
		member.setName("HelloA");
		
		//JPA저장
		em.persist(member); 
		
		//커밋
		tx.commit();
		
		em.close();
		emf.close();
	}

}

 

 

실행하면 h2 데이터베이스에 저장이된걸 확인할 수 있다.

 

 

반응형
LIST

'공부' 카테고리의 다른 글

JPA (2) | JPA 구동방식 설명  (0) 2023.09.20
JPA (1) | 자바 컬렉션과 JPA의 등장배경, JPA 장점  (0) 2023.09.08
클래스 멤버  (0) 2023.07.20
추상 메소드와 인터페이스 | 다중상속  (0) 2023.06.27
다형성  (0) 2023.06.22

 

자바 프로젝트 생성하는데 발생한 오류들 문제해결

 

1. Java Version Mismatch 에러

Java compiler level does not match the version of the installed Java project facet. [프로젝트명] Unknown Faceted Project Problem (Java Version Mismatch)



project - properties 에 들어간다

 

Project Facets 의 자바 버전을 확인

 

Java Compiler 에 JDK 컴파일러 버전을 맞춰준다. 현재 1.7과 11 맞지않기때문에 오류가 난 것

 

 

 

 

2. JSP Problem

The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path index.jsp /ex1-hello-jpa/src/main/webapp line 1 JSP Problem

 

 

project - properties 에 들어간다

 

Java Build Path 에서 Add Library 클릭해서 

 

Server Runtime 클릭하고 tomcat 선택 > Apply

 

반응형
LIST

 

연결을 하면 아래 빨간 박스에 에러메세지가 떴다

Database (디렉토리 경로) not found, either pre-create it or allow remote database creation(not recommended in secure environments)

 

 

 

위처럼 url 창을 localhost 로 수정해보기도 하고, 8082 포트를 지워보기도 하고 , 삭제 하고 다시 다운그레이드를 해보기도 했으나 모두 실패

해결방법은 간단했다

 

 

해결방법

 

두번째 H2 Console이 아닌 첫번째 H2 Command Line 으로 실행하면 된다

 

 

 

 

위 이미지 처럼 JDBC URL에 jdbc:h2:~/test 를 적어주고 연결을 하면 데이터베이스 파일이 생성되면서 연결이 된다. 

 

* DB파일 생성은 * C드라이브 사용자 파일에 위치

 

 

그리고 이후에는 jdbc:h2:tcp://localhost/~/test 을 적어서 연결해주면 된다.

 

 

처음부터 jdbc:h2:tcp://localhost/~/test  연결이 되면 위처럼 할 필요는 없음.

 

 

 


 

재설치 할때 에러

 

1.4.200 버전으로 다운로드를 해보았다

h2 database 다운로드 링크 : https://www.h2database.com/html/download-archive.html

 

 

File corrupted while reading record: null. Possible solution: use the recovery tool 

재설치 했을때 발생한 에러 = 파일이 손상됐다는에러다.

 

 

해결

로컬 디스크의 사용자 폴더에 들어가서 test.mv.db 파일 삭제 (trace.db 도 있길래 삭제 해봄)

 

H2 Console 창 껐다가 다시 실행하기 (근데 위처럼 H2 Command Line으로 실행안해도 된다..?)

 

 

만약 다른에러가 난다면 H2 저장한 폴더위치로 가서 h2.bat 으로 실행하는것도 해결된다

 

 

 


 

다른 h2 데이터 베이스 생성시 오류

 

 

이번에는 jpashop DB 생성시 발생하는 에러

Database (디렉토리 경로) not found, either pre-create it or allow remote database creation(not recommended in secure environments)

 

 

위처럼 H2 Command Line을 실행해봐도 안되고 h2.bat으로 실행해도 안된다..

 

 

해결

숨겨진 아이콘 보기에서 H2 DB 엔진 선택하기

 

처음에 jdbc:h2:tcp://localhost/~/jpashop 했을때 에러가 나면 jdbc:h2:~/jpashop 먼저 해보고 다시 뒤로가기하고 jdbc:h2:tcp://localhost/~/jpashop 로 접속하기!

 

 

 

C:\Users\사용자 에 들어가서 DB 생성된걸 확인할 수 있다.

 

 

반응형
LIST

+ Recent posts