back end/java

spring boot jpa에서 SQLite 사용하는 방법

노루아부지 2022. 10. 8. 22:13
반응형

1. SQLite란?

공식 사이트 : https://sqlite.org/index.html

SQLite는 클라이언트 응용 프로그램에 임베디드 되어 동작하는 DBMS 소프트웨어로서 퍼블릭 도메인 오픈 소스 소프트웨어로 android, iOS, macOS에 기본적으로 포함되어 있습니다.

그래서 SQL에서 하는 기능이 SQLite에선 '경량화'의 이유로 제한되는 경우가 많습니다. 예를 들자면, 프로토콜 조작을 통해 네트워크에 접근할 수는 있지만, 동시 접근은 제한됩니다. 또한 복잡하거나 큰 데이터를 보관하는 데에는 적절하지 않습니다.

또한 데이터베이스 이름 그대로 'lite'이기 때문에 성능은 기대를 하지 않는 것이 좋고, 한 번에 한 명의 사용자만이 데이터베이스를 사용할 수 있어서 멀티 유저를 지원하려면 proxy 계층을 도입해야 합니다.

 

 

2. spring boot jpa에서 SQLite 사용하는 방법

2.1. dependency 설정

여기에서 항상 최신 버전을 확인 하실 수 있습니다.

 

2.1.1. maven

<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
<dependency>
  <groupId>org.xerial</groupId>
  <artifactId>sqlite-jdbc</artifactId>
  <version>3.39.3.0</version>
</dependency>

 

2.1.2 gradle

// https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc
implementation 'org.xerial:sqlite-jdbc:3.39.3.0'

 

 

2.2. Dialect 추가

JPA의 구현체인 hibernate에는 Dialect를 이용해서 다양한 DB의 sql 문법의 차이를 개발자가 신경 쓰지 않도록 변환해줍니다. 그런데 hibernate는 SQLite를 위한 Dialect가 없습니다.
그래서 SQLite를 위한 Dialect를 별도로 추가해야합니다.

import java.sql.Types;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.type.StringType;

public class SQLDialect extends Dialect {

  public SQLDialect() {
    registerColumnType(Types.BIT, "integer");
    registerColumnType(Types.TINYINT, "tinyint");
    registerColumnType(Types.SMALLINT, "smallint");
    registerColumnType(Types.INTEGER, "integer");
    registerColumnType(Types.BIGINT, "bigint");
    registerColumnType(Types.FLOAT, "float");
    registerColumnType(Types.REAL, "real");
    registerColumnType(Types.DOUBLE, "double");
    registerColumnType(Types.NUMERIC, "numeric");
    registerColumnType(Types.DECIMAL, "decimal");
    registerColumnType(Types.CHAR, "char");
    registerColumnType(Types.VARCHAR, "varchar");
    registerColumnType(Types.LONGVARCHAR, "longvarchar");
    registerColumnType(Types.DATE, "date");
    registerColumnType(Types.TIME, "time");
    registerColumnType(Types.TIMESTAMP, "timestamp");
    registerColumnType(Types.BINARY, "blob");
    registerColumnType(Types.VARBINARY, "blob");
    registerColumnType(Types.LONGVARBINARY, "blob");
    // registerColumnType(Types.NULL, "null");
    registerColumnType(Types.BLOB, "blob");
    registerColumnType(Types.CLOB, "clob");
    registerColumnType(Types.BOOLEAN, "integer");

    registerFunction("concat", 
      new VarArgsSQLFunction(StringType.INSTANCE, "", "||", ""));
    registerFunction("mod", 
      new SQLFunctionTemplate(StringType.INSTANCE, "?1 % ?2"));
    registerFunction("substr", 
      new StandardSQLFunction("substr", StringType.INSTANCE));
    registerFunction("substring", 
      new StandardSQLFunction("substr", StringType.INSTANCE));
  }

  public boolean supportsIdentityColumns() {
    return true;
  }

  public boolean hasDataTypeInIdentityColumn() {
    return false; // As specify in NHibernate dialect
  }

  @Override
  public IdentityColumnSupport getIdentityColumnSupport() {
    return new SQLiteIdentityColumnSupport();
  }

  public String getIdentityColumnString() {
    // return "integer primary key autoincrement";
    return "integer";
  }

  public String getIdentitySelectString() {
    return "select last_insert_rowid()";
  }

  public boolean supportsLimit() {
    return true;
  }

  protected String getLimitString(String query, boolean hasOffset) {
    return new StringBuffer(query.length() + 20).append(query)
      .append(hasOffset ? " limit ?, ?" : " limit ?")
      .toString();
  }

  public boolean supportsTemporaryTables() {
    return true;
  }

  public String getCreateTemporaryTableString() {
    return "create temporary table if not exists";
  }

  public boolean dropTemporaryTableAfterUse() {
    return false;
  }

  public boolean supportsCurrentTimestampSelection() {
    return true;
  }

  public boolean isCurrentTimestampSelectStringCallable() {
    return false;
  }

  public String getCurrentTimestampSelectString() {
    return "select current_timestamp";
  }

  public boolean supportsUnionAll() {
    return true;
  }

  public boolean hasAlterTable() {
    return false; // As specify in NHibernate dialect
  }

  public boolean dropConstraints() {
    return false;
  }

  public String getAddColumnString() {
    return "add column";
  }

  public String getForUpdateString() {
    return "";
  }

  public boolean supportsOuterJoinForUpdate() {
    return false;
  }

  public boolean supportsIfExistsBeforeTableName() {
    return true;
  }

  public boolean supportsCascadeDelete() {
    return false;
  }

  @Override
  public String getDropForeignKeyString() {
    return "";
  }

  @Override
  public String getAddForeignKeyConstraintString(String cn,
      String[] fk, String t, String[] pk, boolean rpk) {
    return "";
  }

  @Override
  public String getAddPrimaryKeyConstraintString(String constraintName) {
    return "";
  }
}

 

 

2.3. DB 설정 추가

application.application에 다음과 같이 옵션을 설정합니다.

# SQLite Dialect 지정
spring.jpa.database-platform=com.test.config.SQLDialect 

spring.datasource.url=jdbc:sqlite:mydb.db
spring.datasource.driver-class-name=org.sqlite.JDBC

 

 

 

 

3. Reference

https://namu.wiki/w/SQLite

 

SQLite - 나무위키

이 저작물은 CC BY-NC-SA 2.0 KR에 따라 이용할 수 있습니다. (단, 라이선스가 명시된 일부 문서 및 삽화 제외) 기여하신 문서의 저작권은 각 기여자에게 있으며, 각 기여자는 기여하신 부분의 저작권

namu.wiki

https://skagh.tistory.com/59

 

[spring] spring boot에서 SQLite를 JPA로 사용하기

1. 개요 spring data jpa를 이용하는 Spring boot 프로젝트에서 SQLite를 사용하는 방법에 대해 작성합니다. 2. SQLite란? 공식사이트 : https://sqlite.org/index.html DB-engines(H2 vs SQLite) : https://db-e..

skagh.tistory.com

https://www.baeldung.com/spring-boot-sqlite

 

Spring Boot With SQLite | Baeldung

Configure a Spring Boot application with SQLite persistence

www.baeldung.com

 

728x90
반응형
loading