인프런 커뮤니티 질문&답변

야크쉐이버님의 프로필 이미지

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

기존 테이블이 삭제되지 않는 문제..

해결된 질문

작성

·

16K

6

안녕하세요 영한님

강좌를 보며 예제를 따라하던중 제 프로젝트가 영한님과 다르게 실행되는것 같아

질문을 올립니다

hibernate.hbm2ddl.auto = create 인 상황에서

프로젝트를 실행하면 기존에 생성되었던 엔티티가 삭제 되지 않습니다...

member와 order 엔티티만 @Entity 활성화한 상황인데요

아래 코드 올립니다..

package jpabook.jpashop.domain;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Member {

@Id @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;

@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();

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;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getStreet() {
return street;
}

public void setStreet(String street) {
this.street = street;
}

public String getZipcode() {
return zipcode;
}

public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}

public List<Order> getOrders() {
return orders;
}

public void setOrders(List<Order> orders) {
this.orders = orders;
}
}
package jpabook.jpashop.domain;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "ORDERS")
public class Order {

@Id @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ORDER_ID")
private Long id;

@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;

// @OneToOne
// @JoinColumn(name = "DELIVERY_ID")
// private Delivery delivery;
//
// @OneToMany(mappedBy = "order")
// private List<OrderItem> orderItemList = new ArrayList<>();

private LocalDateTime orderDate;

@Enumerated(EnumType.STRING)
private OrderStatus status;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Member getMember() {
return member;
}

public void setMember(Member member) {
this.member = member;
}

public LocalDateTime getOrderDate() {
return orderDate;
}

public void setOrderDate(LocalDateTime orderDate) {
this.orderDate = orderDate;
}

public OrderStatus getStatus() {
return status;
}

public void setStatus(OrderStatus status) {
this.status = status;
}
}

외래키 제약조건을 삭제하는 순서와 테이블을 삭제하는 순서가 엉켜서 그런것 같은데요;;

어떤방식으로 해결해야 할지 잘 모르겠습니다..

아래에 로그도 올려드립니다..

답변 부탁드립니다..

Hibernate: 

    

    drop table Member if exists

11월 30, 2019 11:39:55 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection

INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@3c321bdb] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.

11월 30, 2019 11:39:55 오후 org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException

WARN: GenerationTarget encountered exception accepting command : Error executing DDL "

    drop table Member if exists" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "

    drop table Member if exists" via JDBC Statement

at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:375)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:359)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:241)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:154)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:126)

at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)

at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:144)

at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)

at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)

at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)

at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)

at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)

at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)

at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)

at jpabook.jpashop.domain.JpaMain.main(JpaMain.java:8)

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Cannot drop "MEMBER" because "FKH0DB7KQR88ED8HQTCQW3JKCIA" depends on it; SQL statement:

    drop table Member if exists [90107-200]

at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)

at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)

at org.h2.message.DbException.get(DbException.java:205)

at org.h2.command.ddl.DropTable.prepareDrop(DropTable.java:98)

at org.h2.command.ddl.DropTable.update(DropTable.java:124)

at org.h2.command.CommandContainer.update(CommandContainer.java:198)

at org.h2.command.Command.executeUpdate(Command.java:251)

at org.h2.server.TcpServerThread.process(TcpServerThread.java:406)

at org.h2.server.TcpServerThread.run(TcpServerThread.java:183)

at java.lang.Thread.run(Unknown Source)

at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)

at org.h2.engine.SessionRemote.done(SessionRemote.java:611)

at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237)

at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:228)

at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201)

at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)

... 15 more

Hibernate: 

    

    drop table ORDERS if exists

Hibernate: 

    

    drop sequence if exists hibernate_sequence

Hibernate: create sequence hibernate_sequence start with 1 increment by 1

11월 30, 2019 11:39:55 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection

INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4ced35ed] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.

Hibernate: 

    

    create table Member (

       MEMBER_ID bigint not null,

        city varchar(255),

        name varchar(255),

        street varchar(255),

        zipcode varchar(255),

        primary key (MEMBER_ID)

    )

11월 30, 2019 11:39:55 오후 org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException

WARN: GenerationTarget encountered exception accepting command : Error executing DDL "

    create table Member (

       MEMBER_ID bigint not null,

        city varchar(255),

        name varchar(255),

        street varchar(255),

        zipcode varchar(255),

        primary key (MEMBER_ID)

    )" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "

    create table Member (

       MEMBER_ID bigint not null,

        city varchar(255),

        name varchar(255),

        street varchar(255),

        zipcode varchar(255),

        primary key (MEMBER_ID)

    )" via JDBC Statement

at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:440)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:424)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:315)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:166)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:135)

at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:121)

at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:155)

at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)

at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)

at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)

at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)

at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)

at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)

at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)

at jpabook.jpashop.domain.JpaMain.main(JpaMain.java:8)

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "MEMBER" already exists; SQL statement:

    create table Member (

       MEMBER_ID bigint not null,

        city varchar(255),

        name varchar(255),

        street varchar(255),

        zipcode varchar(255),

        primary key (MEMBER_ID)

    ) [42101-200]

at org.h2.message.DbException.getJdbcSQLException(DbException.java:453)

at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)

at org.h2.message.DbException.get(DbException.java:205)

at org.h2.message.DbException.get(DbException.java:181)

at org.h2.command.ddl.CreateTable.update(CreateTable.java:89)

at org.h2.command.CommandContainer.update(CommandContainer.java:198)

at org.h2.command.Command.executeUpdate(Command.java:251)

at org.h2.server.TcpServerThread.process(TcpServerThread.java:406)

at org.h2.server.TcpServerThread.run(TcpServerThread.java:183)

at java.lang.Thread.run(Unknown Source)

at org.h2.message.DbException.getJdbcSQLException(DbException.java:453)

at org.h2.engine.SessionRemote.done(SessionRemote.java:611)

at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237)

at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:228)

at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201)

at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)

... 15 more

Hibernate: 

    

    create table ORDERS (

       ORDER_ID bigint not null,

        orderDate timestamp,

        status varchar(255),

        MEMBER_ID bigint,

        primary key (ORDER_ID)

    )

Hibernate: 

    

    alter table ORDERS 

       add constraint FKh0db7kqr88ed8hqtcqw3jkcia 

       foreign key (MEMBER_ID) 

       references Member

11월 30, 2019 11:39:55 오후 org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources

INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@6831d8fd'

Hibernate: 

    call next value for hibernate_sequence

Hibernate: 

    /* insert jpabook.jpashop.domain.Member

        */ insert 

        into

            Member

            (city, name, street, zipcode, MEMBER_ID) 

        values

            (?, ?, ?, ?, ?)

11월 30, 2019 11:39:55 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions

WARN: SQL Error: 23505, SQLState: 23505

11월 30, 2019 11:39:55 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions

ERROR: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.MEMBER(MEMBER_ID) [1, NULL, 'sdfsdf', NULL, NULL]"; SQL statement:

/* insert jpabook.jpashop.domain.Member */ insert into Member (city, name, street, zipcode, MEMBER_ID) values (?, ?, ?, ?, ?) [23505-200]

11월 30, 2019 11:39:55 오후 org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure

ERROR: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]

11월 30, 2019 11:39:55 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop

INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/jpashop]

Process finished with exit code 0

답변 10

32

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요 나땅나땅님^^

문의주셔서 감사합니다. H2 데이터베이스 1.4.200 버전에서 발생하는 문제입니다.

(https://hibernate.atlassian.net/browse/HHH-13711)

해결이 되기 전까지는 H2 데이터베이스 1.4.199를 사용하시길 권장드립니다^^! (현재 1.4.199가 안정화 버전입니다.)

https://www.h2database.com/html/download.html

문의주신 덕분에 고생하시는 다른 분들께도 도움이 될 것 같습니다^^!

감사합니다.

같은 문제로 골머리를 앓고 있었는데 감사합니다

1.4.200 버전을 사용할 경우 하이버네이트 버전을 5.4.13.Final로 하면 됩니다.

21

김영한님의 프로필 이미지
김영한
지식공유자

ㅎㅎ 안녕하세요. 나땅나땅님

정말 열심히 공부하시는군요!

JPA를 공부하는 분 중에 이렇게 많이들 질문을 하세요.

'자바 애플리케이션 개발이 중요해요? DB 관련된 부분을 공부하는게 중요해요?'

사실 질문에 답이 있다고, 둘다 중요합니다.

저도 개인적으로 대용량 데이터베이스 솔루션 책 시리즈를 모두 재미있게 읽어볼 정도로 데이터베이스 관련된 공부를 좋아합니다.

서두가 조금 길었네요 ㅎㅎ

그럼 하나씩 답을 드릴께요

JPA에서는 실행계획을 보고 오라클 힌트와 같은 명령어를 쓰며 튜닝을 할수 없는것인가? 

-> 제가 실무의 다양한 프로젝트를 진행하면서 느낀점은 정말 복잡해서 네이티브 쿼리를 직접 사용해야 하는 경우는 전체의 5% 이하였습니다. JPA도 이런 상황을 대비해서 네이티브 쿼리를 그대로 실행할 수 있게 열어두었습니다. 하이버네이트를 최초로 만든 게빈킹도 하이버네이트로 100%의 문제를 해결하려고 만든 것이 아니라고 했지요. 대부분의 일반적은 쿼리들은 단순하기 때문에 JPA로 쉽게 풀고, 정말 성능이 너무 중요한 포인트에 네이티브 쿼리로 최적화 하는 방안으로 이해하시면 됩니다. 예를 들어서 JPA로 쉽게 했는데, 성능 테스트를 해봤더니 이건 어쩔 수 없이 힌트를 줘야하는 상황이다. 그러면 이제 이 부분만 살짝 네이티브 쿼리로 변경하는 거지요.

다른 강의의 목차에는 인덱스와 같은 언급은 없는것

-> 이 강의는 DB는 어느정도 아신다고 가정하고 JPA에 초점을 맞춘 강의여서 그렇습니다^^ 말씀하신 인덱스 같은 것은 기본입니다. 정말 중요합니다.

 그동안 스터디를 한것이 혹여 근래의 프로젝트들에서는 사용하지 않는것을 공부한것은 아닌가.. 마음졸이며.. 

-> 좋은 질문입니다. 회사마다 조금 다를 수 있는데, 오라클 데이터베이스를 정말 하드하게 쓰는 회사라면 배우신 내용들이 중요하겠지요. 그게 아니라면 배우신 내용을 하나도 못 써먹을 수도 있습니다. 그런데 어떤 데이터베이스를 사용하더라도 배우신 내용이 모두 도움이 되실꺼에요. 개발자라는 직업이 결국 문제를 해결하는 것이 중요한데, 이정도 깊이있게 공부를 해두면 다른 데이터베이스를 사용해도, 문제가 발생했을 때, 아! 그때 스터디했던 그 내용이 떠오르면서, 이 데이터베이스에도 이런 방식으로 튜닝을 해보는 방법이 있지 않을까? 라는 생각이 나실꺼에요. 저도 소시적? 나름 열심히 데이터베이스 공부를 한 덕분에 DB 관련 문제가 생겨도, 어떻게 해결 방안을 찾아야할지 길이 보이더라구요.

그리고 균형도 중요합니다. DB 공부도, 애플리케이션 공부도, 만약 학생이라면 알고리즘 공부도 모두 골고루 해두시면 전부 버릴 곳 없이 도움이 되실꺼에요. 제가 지금까지 만난 개발 잘하는 분들의 특징은 특정 하나만 잘하는게 아니라 다 잘하더라구요.

내용이 좀 길었네요 ㅎㅎ 강의중간 궁금한 내용이 언제든지 편하게 질문주세요^^!

감사합니다.

영한님.. 멋있습니다..ㅠㅠㅠ 실력뿐만 아니라.. 좋으신 분이란게 느껴지네요..ㅎㅎ.. 저도 화이팅하겠습니다~!!

김영한님의 프로필 이미지
김영한
지식공유자

ㅎㅎ 조성우님 감사합니다.

15

https://github.com/hibernate/hibernate-orm/pull/3093

답변이 도움이 될지 모르겠습니다만 h2 버그 + hibernate 버그 둘다인듯 싶고 5.4.13 버전에서 수정됐습니다 :)

사랑합니다

2

김영한님의 프로필 이미지
김영한
지식공유자

ㅎㅎ 공부한 것이 결국 다 쓰일꺼에요. 기술적인 부분보다는 이론적으로 너무 중요한 부분들이어서요!

또 한분야를 깊이있게 하면 다른 분야에도 자연스럽게 연결되더라구요!

그럼 화이팅하세요^^!

2

김영한님의 프로필 이미지
김영한
지식공유자

애플리케이션 로딩 시점에 DROP를 시도하는데, 두번째 부터는 실패해서 오류가 발생하는군요.

우선 로컬에 설치하신 H2 데이터베이스 버전을 알려주세요.

그리고 전체 프로젝트를 압축해서 올려주세요.

 

2

안녕하세요 영한님

늦은시간에 답변감사드립니다

H2에서 모든 테이블을 삭제후 다시 시작하면 처음에는 문제 없이 두 테이블이 생성됩니다.

그리고 바로 뒤에 다시 실행을 하면 같은 에러가 나네요;;

다시 실행해도 DROP하고 CREATE 되야 하는걸로 알고 있는데

DROP 자체가 되지 않는것 같습니다.....

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 나땅나땅님^^

우선 H2 데이터베이스에 들어가서 테이블을 모두 깔끔하게 DROP 한 다음에 다시 시도해보세요^^!

우리가 중간에 코드를 계속 변경하기 때문에 과거 엔티티의 결과가 현재 테이블에 반영되어서 그럴 수 있습니다.

한번 시도해보시고 그래도 잘 안되면 다시 문의주세요^^!

1

아 페이지 다시 보니 h2db dialect 의 버전 호환성 문제네요 여튼 해결된듯 싶습니다 :)

1

영한님 주말 늦은시간에도 이렇게 성의있는 답변을 주셔서 진심으로 감사합니다.

그동안 공부한것이 하나도 못쓰일것이라는 말씀에 조금 마음이 쓰리지만..

영한님도 스터디 후에 어느정도 도움이 되셨다니 위안이 됩니다.

조언해주신것으로 앞으로 어떤 공부를 해야 할지 방향성을 잡을 수 있게 되었습니다.

답변 진심으로 감사드립니다.

좋은밤 되세요~!

 

1

도움을 주셔서 감사합니다 ㅠㅠ 

영한님! 이전 질문과 다르게 여쭤보고 싶은것이 있습니다.

우선 저는 작년부터 SQLP 자격증을 공부하며 오라클성능고도화 책을 보고 있습니다.

오라클 인덱스의 종류나 인덱스 최적화 설계 방법

조인 메커니즘를 NL조인과 HASH 조인등의 차이점 등

실행계획을 보며 힌트 튜닝을 하는법을 스터디 중입니다.

그와 관련하여 제가 궁금한점은

JPA에서는 실행계획을 보고 오라클 힌트와 같은 명령어를 쓰며 튜닝을 할수 없는것인가? 입니다.

그렇다면... 옵티마이저에게 어떻게 인덱스를 강제할지... 의도와 다른 인덱스를 타고 더 느려지는 쿼리에 관련해서는 

어떻게 대응을 할 수 있을지 입니다. 본강의 이외에  올려주신 다른 강의의 목차에는 인덱스와 같은 언급은 없는것 같아서 여쭤

봅니다. 그동안 스터디를 한것이 혹여 근래의 프로젝트들에서는 사용하지 않는것을 공부한것은 아닌가.. 마음졸이며..  질문을 올립니다.

답변부탁드립니다.

 

감사합니다.