JPA로 SQLite 다루기
Python 프로그램의 Embedded DB로 많이 사용되는 SQLite를 Spring 앱에서 JPA로 다루는 방법과 주의점
1. SQLite DB 및 테이블¶
Info
Python으로 SQLite DB를 생성하고 관리하는 방법은 SQLAlchemy, Alembic 기초 활용법 문서, SQLAlchemy로 Python에서 ORM 사용하기문서를 참고하자.
Python으로 관리되는 샘플 테이블 엔티티 클래스는 아래와 같다.
from datetime import datetime
from sqlalchemy import DateTime, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class UserEntity(Base):
__tablename__ = "user_account"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(30))
fullname: Mapped[str | None] = mapped_column(String(50))
created_at: Mapped[datetime] = mapped_column(DateTime)
alembic.ini에 작성한 SQLite DB의 주소는 아래와 같다. Embedded DB이기 때문에 프로그램 내부에 DB를 생성한다.
2. JPA로 SQLite DB 연결¶
SQLite를 사용하기 위한 패키지들의 Gradle 의존성 주입은 아래와 같다.
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.xerial:sqlite-jdbc'
implementation 'org.hibernate.orm:hibernate-community-dialects'
...
}
Spring 애플리케이션 설정을 위한 application.yaml에 SQLite 연결을 위해 작성할 JPA 설정은 아래와 같다.
spring:
jpa:
database-platform: org.hibernate.community.dialect.SQLiteDialect
hibernate:
ddl-auto: validate
datasource:
url: jdbc:sqlite:C:\projects\python312\assets\embedded.db
driver-class-name: org.sqlite.JDBC
Spring 애플리케이션에서 동일한 테이블에 접근하기 위한 JPA 엔티티 클래스는 아래와 같다.
@Data
@Entity
@Table(name = "user_account")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "fullname")
private String fullName;
@Column(name = "created_at")
@CreationTimestamp
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime createdAt;
}
@Converter
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, String> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public String convertToDatabaseColumn(LocalDateTime localDateTime) {
return (localDateTime == null) ? null : localDateTime.format(FORMATTER);
}
@Override
public LocalDateTime convertToEntityAttribute(String dbData) {
return (dbData == null || dbData.isEmpty()) ? null : LocalDateTime.parse(dbData, FORMATTER);
}
}
Tip
SQLAlchemy는 Datetime을 SQlite의 DATETIME 타입으로 매핑하는데, JPA는 LocalDatetime을 SQLite의 TIMESTAMP 타입으로 매핑하기 때문에 AttributeConverter를 통해서 데이터가 적절하게 변환되도록 설정해줘야 한다.