반응형

코프링 강의를 듣는데 강의 h2 세팅이 인메모리로 되어있었다.

이것을 h2 실제 db로 세팅하고 서버를 재실행 해도 데이터를 보존하기 위해 일부 세팅을 바꿔주었다.

[1] h2 연결하기

1. h2 서버 연결

1) h2 실행하기

h2를 다운로드 한 후 파일 내에서 h2.sh 가 있는 곳으로 들어간다. 나의 경우 h2 > bin 에 있었다.

해당 파일이 있는 곳에서 파일을 실행시켜 준다.

./h2.sh

2) h2 db 접속하기

h2를 실행시키면 웹사이트가 열린다. db url을 입력해야 하는데 첫 연결시에는 해당 경로로 db가 생성된다.

나는 root경로 하위에 생성하도록 했다. 이후 연결 을 눌러 연결해 준다. 그러면 사이트 창이 하나 열리는데 화면 로딩이 안될 경우 해당 인터넷 창의 url 앞부분의 ip 주소 부분을 localhost로 변경해준다.

key 부분은 절대 수정하면 안된다!

http://localhost:8082/login.do?jsessionid=~~~~~

그렇게 되면 초기 화면을 볼 수 있다. 이후 재 연결시에는 tcp를 통해 연결해주도록 한다.

[2] h2연결을 위한 프로젝트 설정

1. application 설정 파일 수정 : yml 버전

먼저 application.yml에서 database의 설정을 변경해 준다.

기존에 프로젝트 소스코드에서는 인메모리 형식으로 지정되어 있었다.

spring:
  datasource:
    url: 'jdbc:h2:mem:library'
    username: 'user'
    password: ''
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        format_sql: true
        show_sql: true

간단하게 설명하자면

datasource에서 url이 h2 db의 접속 경로이다. :mem: 으로 되어있어 인메모리 db를 사용하는 것을 뜻한다.

jpa > hibername > ddl-auto 에는 크게 create와 none이 있다. create를 하면 서버를 재실행 할때마다 데이터를 리셋하면서 테이블 세팅을 다시 하는것이고, none이면 기존 설정을 유지하는 것이다.

만약 설정이 create 이고, 기존 테이블의 이름을 소스상에서 변경처리후 서버를 재실행 하면 기존 테이블 명으로도 남아있고, 새로운 테이블 명으로도 테이블이 생성된다.

 

위 설정값을 아래로 변경해 준다. tcp 통신을 통해 연결하므로 동시성 문제도 해결되는것으로 알고 있다.

spring:
  datasource:
    url: 'jdbc:h2:tcp://localhost/~/library'
    username: 'user'
    password: ''
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        format_sql: true
        show_sql: true
logging.level:
  org.hibernate.SQL: debug

db의 CRUD 쿼리를 보기 위해 log 설정을 추가해 주었다.

 

2. 스프링 서버 실행하기

위에 log 설정을 해두었기 때문에 프로젝트 실행 시 h2 db의 테이블 세팅 쿼리가 보여진다.

 

[3] USER 테이블 미생성 오류

bookuser_loan_history 라는 테이블은 클래스명 대로 잘 생성되었는데 user 테이블은 생성이 안되었다.

로그를 살펴보니 아래와 같은 에러메세지가 보인다.

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "\000a    create table [*]user (\000a       id bigint generated by default as identity,\000a        age integer,\000a        name varchar(255) not null,\000a        primary key (id)\000a    )"; expected "identifier"; SQL statement:

    create table user (
       id bigint generated by default as identity,
        age integer,
        name varchar(255) not null,
        primary key (id)
    ) [42001-200]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:453) ~[h2-1.4.200.jar:1.4.200]

하지만 user 클래스는 @Entity 어노테이션도 잘 붙어있고, id 값에는 @GeneratedValue 로 제대로 세팅되어있는것으로 보인다.

@Entity
public class User {

  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;
}

 

> 예약어 : USER

이거저거 검색해보니 해당 클래스 명이 USER인데 이 USER라는 값은 mysql의 예약어 라고 한다. 때문에 개발자가 사용 불가능한 값이므로 해당 값을 테이블명으로 세팅할수 없다고 한다.

https://dev.mysql.com/doc/refman/8.0/en/keywords.html#keywords-in-current-series

 

클래스 명을 변경하기엔 다른 코드도 전부 수정해주어야 해서 안될것 같아 @Table 어노테이션을 사용하였다.

 

> @Table 어노테이션

해당 어노테이션의 parameter 값으로 name을 설정할 수 있다. 해당 값을 입력해두면 테이블 생성시 입력한 값으로 테이블 명이 지정된다.

예약어 이슈를 회피하기 위해 다음과 같이 설정해 주었다. 어노테이션을 붙여주면서 user 테이블의 이름을 복수형으로 지정했기 때문에 book 테이블 명도 복수형으로 지정해 주었다. 

@Entity
@Table(name="users")
public class User {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;
}

 

> 서버 재실행 후 테이블 생성 확인

이후 서버를 재 실행 해준다!

이때 ddl-auto 의 값은 create 여야 변경된 테이블 정보가 적용된다.

또한, 이전에 생성된 BOOK 테이블을 버리고 복수형으로 지정된 테이블을 생성하기 위해서 h2 에서 table drop 쿼리를 날려준다.

drop table if exists BOOK
drop table if exists USER_LOAN_HISTORY

그리고 서버를 실행해준다.

 

!! 테이블 명을 @Table 어노테이션으로 "소문자" 로 적어도 테이블 생성시 대문자로 생성된다!!

 

성공적으로 테이블이 생성되었다!

이후 application.yml 파일에서 ddl-auto 설정을 none 으로 해주어 서버 재 실행시에도 데이터가 날아가지 않도록 해준다!

반응형

+ Recent posts