ALTER TABLE 하위에나 UPDATE, DELETE가 있지, 레코드를 수정/삭제하는 SQL은 없다clickhouse-serverdocker run -p 8123:8123 -p 9000:9000 -d --name some-clickhouse-server --ulimit nofile=262144:262144 --volume=C:\PATH\TO\ANY\WHERE:/var/lib/clickhouse yandex/clickhouse-server
8123 포트: HTTP 인터페이스 위한 포트9000 포트: clickhouse-client 위한 포트clickhouse-clientdocker run -it --rm --link some-clickhouse-server:clickhouse-server yandex/clickhouse-client --host clickhouse-server
CREATE DATABASE test_db ENGINE = Atomic COMMENT 'test clickhouse db';
CREATE TABLE IF NOT EXISTS test_db.test_table
(
`c_int8` Int8,
`c_int16` Int16,
`c_int32` Int32,
`c_int64` Int64,
`c_int128` Int128,
`c_int256` Int256,
`c_float32` Float32,
`c_float64` Float64,
`c_decimal32_9` Decimal32(9),
`c_decimal64_18` Decimal64(18),
`c_decimal128_38` Decimal128(38),
`c_decimal256_76` Decimal256(76),
`c_string` String,
`c_fixedstring` FixedString(2),
`c_date` Date,
`c_date32` Date32,
`c_datetime` DateTime('Asia/Seoul'),
`c_datetime64` DateTime64(3, 'Asia/Seoul'),
`c_array_int8` Array(Int8),
`c_array_int16` Array(Int16),
`c_array_string` Array(String),
`c_nested` Nested(nested_c_int32 Int32, nested_c_array_int16 Array(Int16), nested_c_array_string Array(String)),
`c_tuple` Tuple(Nullable(String), Nullable(String))
)
ENGINE = MergeTree()
PRIMARY KEY c_int8;
INSERT INTO test_db.test_table (c_int8, c_int16, c_int32, c_int64, c_int128, c_int256, c_float32, c_float64,
c_decimal32_9, c_decimal64_18, c_decimal128_38, c_decimal256_76, c_string,
c_fixedstring, c_date, c_date32, c_datetime, c_datetime64, c_array_int8, c_array_int16,
c_array_string, c_nested.nested_c_int32, c_nested.nested_c_array_int16,
c_nested.nested_c_array_string, c_tuple)
VALUES (1, 32767, 2147483647, 9223372036854775807, 170141183460469231731687303715884105727,
57896044618658097711785492504343953926634992332820282019728792003956564819967, 0.09999999999999998,
0.09999999999999998, 0.9999, 0.999999999, 0.99999999999999, 0.99999999999999999999, 'string test', 'fs',
1546300800, 4102444800, 1546300800, 1546300800000, array(1, 2, 3), array(100, 1000, 10000),
array('test', 'string', 'array'), null, null, null, tuple('key1', 'value1'));
main.java.com.learn.spring.learnspring
.config
ㄴClickhouseDataSourceConfig
.entities
.clickhouse
ㄴpackage-info.java
ㄴTestTableChildEntity
ㄴTestTableEntity
ㄴTestTableParentEntity
.repository
.clickhouse
ㄴTestTableRepository
ㄴTestTableSubRepository
test.java.com.learn.spring.learnspring
.repository.clickhouse
ㄴTestTableRepositoryTest
build.gradleplugins {
id 'org.springframework.boot' version '2.6.2'
id "io.spring.dependency-management" version "1.0.11.RELEASE"
id 'java'
id 'idea'
}
group = 'com.learn.spring'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.15'
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
// postgresql jdbc 사용하기 위한 의존성
implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.9'
// groovy 템플릿
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.9'
// 오브젝트의 값을 JSON으로 바인딩
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.1'
// @JsonFormat 어노테이션 사용해서 Java8 버전의 date와 time 클래스를 JSON으로 변환하는 것을 도와준다
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.13.1'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-jaxb-annotations
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-jaxb-annotations', version: '2.13.1'
compileOnly 'org.projectlombok:lombok'
// implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-web-services'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.session:spring-session-core'
implementation 'com.squareup.okhttp3:okhttp:4.9.3' // RestTempalte 대신
// https://mvnrepository.com/artifact/ru.yandex.clickhouse/clickhouse-jdbc
implementation group: 'ru.yandex.clickhouse', name: 'clickhouse-jdbc', version: '0.3.2'
// https://mvnrepository.com/artifact/com.vladmihalcea/hibernate-types-55
implementation group: 'com.vladmihalcea', name: 'hibernate-types-55', version: '2.14.0'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
ClickhouseDataSourceConfig.javapackage com.learn.spring.learnspring.config;
import com.clickhouse.client.config.ClickHouseClientOption;
import com.clickhouse.jdbc.ClickHouseDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
@Slf4j
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "clickhouseEntityManager",
transactionManagerRef = "clickhouseTransactionManager",
basePackages = {
"com.learn.spring.learnspring.entities.clickhouse",
"com.learn.spring.learnspring.repository.clickhouse"
}
)
@RequiredArgsConstructor
public class ClickhouseDataSourceConfig {
@Value("${spring.datasource.clickhouse1.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.clickhouse1.url}")
private String url;
@Value("${spring.datasource.clickhouse1.database}")
private String database;
@Value("${spring.datasource.clickhouse1.username}")
private String username;
@Value("${spring.datasource.clickhouse1.password}")
private String password;
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
/**
* https://github.com/ClickHouse/clickhouse-jdbc/blob/d6bcbe412d4c7310bba7dc4b0334140b04614004/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/JdbcIntegrationTest.java#L106
* @return
* @throws SQLException
*/
public DataSource getClickhouseDataSource() throws SQLException {
Properties properties = new Properties();
properties.setProperty(ClickHouseClientOption.DATABASE.getKey(), database);
properties.setProperty(ClickHouseClientOption.CLIENT_NAME.getKey(), username);
properties.setProperty("user", username);
properties.setProperty("password", password);
return new ClickHouseDataSource(url, properties);
}
@Bean(name = "clickhouseDataSource")
public DataSource clickhouseDataSource() throws SQLException {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDataSource(getClickhouseDataSource());
hikariConfig.setPoolName("clickhouseDataSourcePool");
hikariConfig.setDriverClassName(driverClassName);
return new HikariDataSource(hikariConfig);
}
@Bean(name = "clickhouseEntityManager")
public LocalContainerEntityManagerFactoryBean clickhouseEntityManager(EntityManagerFactoryBuilder builder) throws SQLException {
return builder
.dataSource(clickhouseDataSource())
.properties(getVendorProperties())
.packages("com.learn.spring.learnspring.entities.clickhouse")
.persistenceUnit("clickhouseEntityManager")
.build();
}
private Map<String, Object> getVendorProperties() {
Map<String,String> properties=jpaProperties.getProperties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
return hibernateProperties.determineHibernateProperties(
properties, new HibernateSettings());
}
@Bean(name = "clickhouseTransactionManager")
public PlatformTransactionManager clickhouseTransactionManager(LocalContainerEntityManagerFactoryBean clickhouseEntityManager) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(clickhouseEntityManager.getObject());
return txManager;
}
}
ClickHouseDataSource
clickhouse-jdbc 라이브러리에서 제공하는 DataSource 인터페이스 구현 클래스DataSource? 물리적인 데이터 소스로의 연결을 제공하는 팩토리. Connection 인터페이스 구현한 ClickHouseConnectionImpl 인스턴스 반환HikariDataSource
Connection을 무한정 추가할 수 없으므로, 일정한 데이터 소스 연결을 pooling하기 위한 데이터 소스LocalContainerEntityManagerFactoryBean
EntityManagerFactory를 생성해주는 FactoryBean 인터페이스의 구현 클래스LocalContainerEntityManagerFactoryBean과 LocalEntityManagerFactoryBean의 차이?
LocalContainerEntityManagerFactoryBean는 컨테이너가 관리하는 팩토리 빈LocalEntityManagerFactoryBean는 application, 즉 개발자의 코드가 관리하는 팩토리 빈EntityManagerFactory 생성 방식이 유일한 차이점이라고 한다EntityManagerFactoryBuilder
LocalContainerEntityManagerFactoryBean을 fluent builder pattern 방식으로 생성할 수 있도록 해주는 빌더dataSource(${DATASOURCE}) 호출하면 EntityManagerFactoryBuilder.Builder 인스턴스 반환하고, 빌드해 나간다getVendorProperties()
org.hibernate.dialect.MySQLDialect 사용PlatformTransactionManager
TransactionTemplate 인스턴스가 트랜잭션을 생성, 커밋, 롤백하는 것을 도와주는 클래스
TransactionTemplate? 프로그램적인 트랜잭션 구별(transaction demarcation)과 예외 처리를 간소화해주는 템플릿 클래스정리를 하자면,
이때, 1, 2, 3이 데이터베이스 연결과 직접적으로 관련되어 있고, 그 후 4에서 트랜잭션 관리 위한 인스턴스를 생성하게 된다
참고로 @Value 어노테이션의 경우, 빈 메서드에 @ConfigurationProperties 어노테이션 통해 필요한 Properties 인스턴스 생성해서 반환하도록 하여 대체할 수도 있다.
hibernate-types@OneToMany나 @ManyToOne 관계는 아니고, @ElementCollection 같은 어노테이션을 사용해야 한다hibernate-types가 있어서 이를 통해 JPA 결과를 Entity로 맵핑해봤고, 실제로 편했다.package-info.java@Type을 정의하는 데 사용@TypeDefs({
@TypeDef(
name = "json", typeClass = JsonType.class
),
@TypeDef(
name = "list-array", typeClass = ListArrayType.class
)
})
package com.learn.spring.learnspring.entities.clickhouse;
import com.vladmihalcea.hibernate.type.array.ListArrayType;
import com.vladmihalcea.hibernate.type.json.JsonStringType;
import com.vladmihalcea.hibernate.type.json.JsonType;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
TestTableEntitypackage com.learn.spring.learnspring.entities.clickhouse;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@Getter
@Setter
@Entity
@Table(name = "test_table", schema = "test_db")
public class TestTableEntity implements Serializable {
@Basic
@Id
@Column(name = "c_int8", columnDefinition = "tinyint")
private Integer id; // cInt8에서 id로 이름을 바꾸고, TestTableRepository에서도 바꾸니 정상 실행
@Basic
@Column(name = "c_int16", columnDefinition = "int16")
private Integer cInt16;
@Basic
@Column(name = "c_int32", columnDefinition = "int32")
private Integer cInt32;
@Basic
@Column(name = "c_int64", columnDefinition = "int64")
private Long cInt64;
@Basic
@Column(name = "c_int128", columnDefinition = "int128")
private BigDecimal cInt128;
@Basic
@Column(name = "c_int256", columnDefinition = "int256")
private BigDecimal cInt256;
@Basic
@Column(name = "c_float32", columnDefinition = "float32")
private Float cFloat32;
@Basic
@Column(name = "c_float64", columnDefinition = "float64")
private Float cFloat64;
@Basic
@Column(name = "c_decimal32_9", columnDefinition = "Decimal(9,9)")
private BigDecimal cDecimal329;
@Basic
@Column(name = "c_decimal64_18", columnDefinition = "Decimal(18,18)")
private BigDecimal cDecimal6418;
@Basic
@Column(name = "c_decimal128_38", columnDefinition = "Decimal(38,38)")
private BigDecimal cDecimal12838;
@Basic
@Column(name = "c_decimal256_76", columnDefinition = "Decimal(76,76)")
private BigDecimal cDecimal25676;
@Basic
@Column(name = "c_string", columnDefinition = "string")
private String cString;
@Basic
@Column(name = "c_fixedstring", columnDefinition = "fixedstring")
private String cFixedstring;
@Basic
@Column(name = "c_date", columnDefinition = "date")
private LocalDateTime cDate;
@Basic
@Column(name = "c_date32", columnDefinition = "date32")
private LocalDateTime cDate32;
@Basic
@Column(name = "c_datetime", columnDefinition = "datetime")
private LocalDateTime cDatetime;
@Basic
@Column(name = "c_datetime64", columnDefinition = "datetime64")
private LocalDateTime cDatetime64;
@Basic
@Column(name = "c_array_int8", columnDefinition = "array")
@Type(type = "json")
private List<Short> cArrayInt8;
@Basic
@Column(name = "c_array_int16", columnDefinition = "array")
@Type(type = "json")
private List<Integer> cArrayInt16;
@Basic
@Column(name = "c_array_string", columnDefinition = "array")
@Type(type = "list-array")
private List<String> cArrayString;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
TestTableEntity that = (TestTableEntity) o;
return id != null && Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
columnDefinition은 일일이 지정하지 않아도 되는데, 만약 application.yml에서 spring.jpa.hibernate.ddl-auto: validate 설정을 한다면 타입 검증을 빡쎄게 하기 때문에 클릭하우스에서 실제로 어떤 타입인지를 명시해줘야 한다TestTableRepositorypackage com.learn.spring.learnspring.repository.clickhouse;
import com.learn.spring.learnspring.entities.clickhouse.TestTableEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TestTableRepository extends JpaRepository<TestTableEntity, Short> {
List<TestTableEntity> findById(Integer id);
}
package com.learn.spring.learnspring.repository.clickhouse;
import com.learn.spring.learnspring.entities.clickhouse.TestTableEntity;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@ActiveProfiles({"dev"})
class TestTableRepositoryTest {
@Autowired
private TestTableRepository testTableRepository;
@Test
@DisplayName("Retrieve TestDataEntity from ClickHouse Using JPA")
void TestTableEntity_Returns_TestTableEntity() {
List<TestTableEntity> results = testTableRepository.findById(1);
ArrayList<String> expected = new ArrayList<>();
expected.add("test");
expected.add("string");
expected.add("array");
Assertions.assertEquals(expected, results.get(0).getCArrayString());
System.out.println(results.get(0).getCInt256());
}
}
위와 같이 큰 수를 출력해보면, 아래와 같이 57896044618658097711785492504343953926634992332820282019728792003956564819967가 출력된다
2022-01-06 00:29:33.546 INFO --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-01-06 00:29:33.567 INFO --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'clickhouseEntityManager'
2022-01-06 00:29:35.367 INFO --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@317fa5dd, org.springframework.security.web.context.SecurityContextPersistenceFilter@7ce760af, org.springframework.security.web.header.HeaderWriterFilter@1e160a9e, org.springframework.web.filter.CorsFilter@477906cf, org.springframework.security.web.csrf.CsrfFilter@346e5cc, org.springframework.security.web.authentication.logout.LogoutFilter@c31419f, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6686507b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@72c5064f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@65234a9, org.springframework.security.web.session.SessionManagementFilter@5e6bbe63, org.springframework.security.web.access.ExceptionTranslationFilter@1a7437d8]
2022-01-06 00:29:38.925 INFO --- [ main] c.l.s.l.r.c.TestTableRepositoryTest : Started TestTableRepositoryTest in 12.463 seconds (JVM running for 15.362)
57896044618658097711785492504343953926634992332820282019728792003956564819967
2022-01-06 00:29:39.948 INFO --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'clickhouseEntityManager'
2022-01-06 00:29:39.950 INFO --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : clickhouseDataSourcePool - Shutdown initiated...
2022-01-06 00:29:39.959 INFO --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : clickhouseDataSourcePool - Shutdown completed.
@MappedSuperclass 통한 상속 구조TestTableParentEntitypackage com.learn.spring.learnspring.entities.clickhouse;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@Getter
@Setter
@MappedSuperclass
@EqualsAndHashCode
public class TestTableParentEntity implements Serializable {
@Basic
@Column(name = "c_int16", columnDefinition = "int16")
private Integer cInt16;
@Basic
@Column(name = "c_int32", columnDefinition = "int32")
private Integer cInt32;
@Basic
@Column(name = "c_int64", columnDefinition = "int64")
private Long cInt64;
@Basic
@Column(name = "c_int128", columnDefinition = "int128")
private BigDecimal cInt128;
@Basic
@Column(name = "c_int256", columnDefinition = "int256")
private BigDecimal cInt256;
@Basic
@Column(name = "c_float32", columnDefinition = "float32")
private Float cFloat32;
@Basic
@Column(name = "c_float64", columnDefinition = "float64")
private Float cFloat64;
@Basic
@Column(name = "c_decimal32_9", columnDefinition = "Decimal(9,9)")
private BigDecimal cDecimal329;
@Basic
@Column(name = "c_decimal64_18", columnDefinition = "Decimal(18,18)")
private BigDecimal cDecimal6418;
@Basic
@Column(name = "c_decimal128_38", columnDefinition = "Decimal(38,38)")
private BigDecimal cDecimal12838;
@Basic
@Column(name = "c_decimal256_76", columnDefinition = "Decimal(76,76)")
private BigDecimal cDecimal25676;
@Basic
@Column(name = "c_string", columnDefinition = "string")
private String cString;
@Basic
@Column(name = "c_fixedstring", columnDefinition = "fixedstring")
private String cFixedstring;
@Basic
@Column(name = "c_date", columnDefinition = "date")
private LocalDateTime cDate;
@Basic
@Column(name = "c_date32", columnDefinition = "date32")
private LocalDateTime cDate32;
@Basic
@Column(name = "c_datetime", columnDefinition = "datetime")
private LocalDateTime cDatetime;
@Basic
@Column(name = "c_datetime64", columnDefinition = "datetime64")
private LocalDateTime cDatetime64;
@Basic
@Column(name = "c_array_int8", columnDefinition = "array")
@Type(type = "json")
private List<Short> cArrayInt8;
@Basic
@Column(name = "c_array_int16", columnDefinition = "array")
@Type(type = "json")
private List<Integer> cArrayInt16;
@Basic
@Column(name = "c_array_string", columnDefinition = "array")
@Type(type = "list-array")
private List<String> cArrayString;
}
@Entity 및 @Table 어노테이션 제거하고, 실제로 사용할 하위 엔터티에 추가해준다@MappedSuperclass 어노테이션 사용해서 연관관계 맵핑이 아닌 단일 테이블을 상속 구조로 변경함을 나타낸다
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 같은 어노테이션 사용해야 한다TestTableChildEntitypackage com.learn.spring.learnspring.entities.clickhouse;
import javax.persistence.*;
@Entity
@Table(name = "test_table", schema = "test_db") // database를 test_db로 지정했기 때문에 사실 필요 없다
public class TestTableChildEntity extends TestTableParentEntity{
@Basic
@Id
@Column(name = "c_int8", columnDefinition = "tinyint")
private Integer id; // cInt8에서 id로 이름을 바꾸고, TestTableRepository에서도 바꾸니 정상 실행
}
TestTableSubRepositorypackage com.learn.spring.learnspring.repository.clickhouse;
import com.learn.spring.learnspring.entities.clickhouse.TestTableChildEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TestTableSubRepository extends JpaRepository<TestTableChildEntity, Short> {
List<TestTableChildEntity> findById(Integer id);
}
ClickhouseDataSourceConfig에서 해당 Repository용 데이터 소스 구성을 따로 해줘야 한다.Multitenancy 개념 통해서 여러 클라이언트(혹은 입주자 tenant)를 제공할 수 있도록 해야 한다.@Test
@DisplayName("Retrieve TestDataSubEntity from ClickHouse Using JPA")
void TestTableSubEntity_Returns_TestTableSubEntity() {
List<TestTableChildEntity> results = testTableSubRepository.findById(1);
ArrayList<String> expected = new ArrayList<>();
expected.add("test");
expected.add("string");
expected.add("array");
Assertions.assertEquals(expected, results.get(0).getCArrayString());
System.out.println(results.get(0).getCInt256());
}
2022-01-06 00:43:55.618 INFO --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'clickhouseEntityManager'
2022-01-06 00:43:57.160 INFO --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4bec6682, org.springframework.security.web.context.SecurityContextPersistenceFilter@2c6efee3, org.springframework.security.web.header.HeaderWriterFilter@792b9dd3, org.springframework.web.filter.CorsFilter@2d97344c, org.springframework.security.web.csrf.CsrfFilter@123d0816, org.springframework.security.web.authentication.logout.LogoutFilter@e2ee348, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3163e03b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@56adbb07, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@7f839ec5, org.springframework.security.web.session.SessionManagementFilter@2b4ba2d9, org.springframework.security.web.access.ExceptionTranslationFilter@38c1b1a7]
2022-01-06 00:44:00.670 INFO --- [ main] c.l.s.l.r.c.TestTableRepositoryTest : Started TestTableRepositoryTest in 11.408 seconds (JVM running for 13.875)
57896044618658097711785492504343953926634992332820282019728792003956564819967
2022-01-06 00:44:01.821 INFO --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'clickhouseEntityManager'
2022-01-06 00:44:01.825 INFO --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : clickhouseDataSourcePool - Shutdown initiated...
2022-01-06 00:44:01.830 INFO --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : clickhouseDataSourcePool - Shutdown completed.