서문: 이 슬라이싱 알고리즘은 슬라이싱 Jian을 수행하는 시간을 기반으로 합니다. 예를 들어 하나의 테이블을 3일 동안 또는 하나의 테이블을 5일 동안 사용하려는 경우 데이터의 양에 따라 동적으로 구성할 수 있습니다. 다음 코드 조각, 전체 코드는 깃허브의 [코드 링크]에서 확인할 수 있습니다. 코드 구조는 아래와 같습니다:
I. 종속성 추가
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<!-- <version>5.2.4</version>-->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.5</version>
</dependency>
<!-- https://.com/artifact/.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!--데이터베이스 연결은 mysql로 --.>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.0</version>
</dependency>
<!-- ShardingJDBC 5.1.0드루이드 연결 풀링을 사용하려면 dbcp 종속성을 추가해야 합니다.>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version></version>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<!-- Mybatis에 대한 페이징 플러그인 --.>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>2.6.4</version>
</dependency>
</dependencies>
구성 파일 추가하기
- 데이터베이스 측의 구성은 기본적으로 정상적으로 추가할 수 있습니다. 기본적으로 드루이드를 사용한 연결 풀링이 사용됩니다.
- 슬라이싱 규칙과 관련된 구성입니다:
# 샤딩을 위한 실제 테이블, 물리적 테이블
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=ifaas_client.t_user
# 샤딩이 수행되는 샤딩 테이블의 필드, 샤딩 수행 기준
spring.shardingsphere.rules.sharding.tables.t_user.table-strategy.standard.sharding-column=create_time
# 샤딩 알고리즘의 이름
spring.shardingsphere.rules.sharding.tables.t_user.table-strategy.standard.sharding-algorithm-name=time-sharding-algorithm
# 샤딩 테이블의 기본 키는 다음과 같습니다.,
spring.shardingsphere.rules.sharding.tables.t_user.key-generate-strategy.column=id
# 샤딩 테이블의 기본 키를 생성하는 로직으로, 기본값은 기본 키 충돌을 방지하기 위해 눈송이 알고리즘을 사용합니다.
spring.shardingsphere.rules.sharding.tables.t_user.key-generate-strategy.key-generator-name=snowflake
# 기본 유형에 따른 시간 분할 테이블의 유형
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.type=CLASS_BASED
# 샤딩 테이블의 모드는 표준 모드입니다.
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.props.strategy=standard
# 테이블을 샤딩하는 알고리즘의 이름으로, 샤딩 알고리즘의 클래스 이름인 TimeShardingAlgorithm에 해당하며 대문자가 없고 짧은 캐리로 연결된 험프가 있습니다.
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.props.algorithmClassName=com.yuzi.sharding.TimeShardingAlgorithm
server.port=9002
spring.application.name=ifaas-file
eureka.client.service-url.defaultZone = "http://...1:9725"/eureka/
eureka.instance.lease-expiration-duration-in-seconds = 65
eureka.instance.lease-renewal-interval-in-seconds = 20
eureka.client.healthcheck.enabled = true
eureka.instance.prefer-ip-address = true
spring.main.allow-bean-definition-overriding=true
spring.main.allow-circular-references=true
spring.datasource.host=jdbc:mysql://localhost:3306
spring.datasource.url = ${spring.datasource.host}/ifaas_client?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Tokyo
spring.datasource.password = 123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username = root
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.max-lifetime=2000
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.datasource.names=mydb
spring.shardingsphere.datasource.mydb.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.mydb.url=${spring.datasource.host}/ifaas_client?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Tokyo
spring.shardingsphere.datasource.mydb.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.mydb.username=root
spring.shardingsphere.datasource.mydb.password=123456
spring.shardingsphere.datasource.mydb.initial-size=5
spring.shardingsphere.datasource.mydb.min-idle=5
spring.shardingsphere.datasource.mydb.max-active=20
spring.shardingsphere.datasource.mydb.max-wait=60000
spring.shardingsphere.datasource.mydb.time-between-eviction-runs-millis=60000
spring.shardingsphere.datasource.mydb.min-evictable-idle-time-millis=300000
spring.shardingsphere.datasource.mydb.validation-query=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.mydb.test-while-idle=true
spring.shardingsphere.datasource.mydb.test-on-borrow=false
spring.shardingsphere.datasource.mydb.test-on-return=false
spring.shardingsphere.datasource.mydb.pool-prepared-statements=true
spring.shardingsphere.datasource.mydb.max-pool-prepared-statement-per-connection-size=20
spring.shardingsphere.datasource.mydb.use-global-data-source-stat=true
spring.shardingsphere.datasource.mydb.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
spring.shardingsphere.rules.sharding.tables.t_user.actual-data-nodes=ifaas_client.t_user
spring.shardingsphere.rules.sharding.tables.t_user.table-strategy.standard.sharding-column=create_time
spring.shardingsphere.rules.sharding.tables.t_user.table-strategy.standard.sharding-algorithm-name=time-sharding-algorithm
spring.shardingsphere.rules.sharding.tables.t_user.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.t_user.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.type=CLASS_BASED
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.props.strategy=standard
spring.shardingsphere.rules.sharding.sharding-algorithms.time-sharding-algorithm.props.algorithmClassName=com.yuzi.sharding.TimeShardingAlgorithm
mybatis-plus.mapper-locations=classpath*:mybatis/mapper/*.xml
mybatis-plus.type-aliases-package.yuzi.entity
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
pagehelper.helperDialect=postgresql
spring.flyway.enabled= true
spring.flyway.encoding= UTF-8
spring.flyway.locations=classpath:db/migration
spring.flyway.url= jdbc:mysql://localhost:3306/ifaas_client?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Tokyo
spring.flyway.user= root
spring.flyway.password= 123456
, 하위 테이블의 핵심 로직인 슬라이싱 알고리즘을 작성합니다.
이 샤딩 알고리즘은 샤딩 키로 시간을 사용하는 샤딩으로, 샤딩의 시간 범위가 설정에 지원되는 샤딩 알고리즘 인터페이스 표준샤딩알고리즘을 구현하는 데 필요한 타임샤딩알고리즘 클래스입니다.
@Slf4j
public class TimeShardingAlgorithm implements StandardShardingAlgorithm<LocalDateTime> {
/**
* 테이블 샤딩 표기법, 예: t_contract_202201 샤딩 기호가 "_"
*/
private final String TABLE_SPLIT_SYMBOL = "_";
/**
* 정밀 샤딩
* @param tableNames 해당 샤딩 라이브러리에 있는 모든 샤딩 테이블의 모음입니다.
* @param preciseShardingValue 여기서 logicTableName은 논리적 테이블, columnName은 샤딩 키, value는 SQL에서 파싱된 샤딩 키의 값입니다.
* @return
*/
@Override
public String doSharding(Collection<String> tableNames, PreciseShardingValue<LocalDateTime> preciseShardingValue) {
String logicTableName = preciseShardingValue.getLogicTableName();
ShardingTableCacheEnum logicTable = ShardingTableCacheEnum.of(logicTableName);
if (logicTable == null) {
log.error(">>>>>>>>>> ERROR데이터 테이블 유형이 잘못되었습니다. 나중에 다시 시도하세요. 로그 테이블 이름:{},logicTableName:{}",
ShardingTableCacheEnum.logicTableNames(), logicTableName);
throw new IllegalArgumentException("데이터 테이블 유형 오류, 나중에 다시 시도하세요");
}
// 히트 샤딩 테이블 결정
LocalDateTime dateTime = preciseShardingValue.getValue();
String resultTableName = getActualTable(logicTable, dateTime);
if (StringUtils.isBlank(resultTableName)){
// 샤딩 테이블이 존재하지 않는 경우 기본 테이블을 반환합니다.
resultTableName = logicTableName + TABLE_SPLIT_SYMBOL + "0";
}
// 샤딩 정보 인쇄
log.info(">>>>>>>>>> INFO논리적 테이블을 사용한 정밀한 샤딩:{},물리적 테이블:{}", logicTableName, resultTableName);
return resultTableName;
}
/**
* 범위 슬라이싱
* @param tableNames 해당 샤딩 라이브러리에 있는 모든 샤딩 테이블의 모음입니다.
* @param rangeShardingValue 샤딩 범위
* @return 테이블 이름 모음
*/
@Override
public Collection<String> doSharding(Collection<String> tableNames, RangeShardingValue<LocalDateTime> rangeShardingValue) {
String logicTableName = rangeShardingValue.getLogicTableName();
ShardingTableCacheEnum logicTable = ShardingTableCacheEnum.of(logicTableName);
if (logicTable == null) {
log.error(">>>>>>>>>> ERROR논리 테이블 범위 예외, 나중에 다시 시도하세요. 논리 테이블 이름:{},logicTableName:{}",
ShardingTableCacheEnum.logicTableNames(), logicTableName);
throw new IllegalArgumentException("논리적 테이블 범위 예외, 나중에 다시 시도하세요");
}
// 샤딩 테이블 범위의 주기적 계산
Set<String> resultTableNames = getActualTableSet(logicTable,rangeShardingValue.getValueRange());
if (CollectionUtils.isEmpty(resultTableNames)){
// 기본 테이블이 존재하지 않는 경우 기본 테이블 반환
resultTableNames = new HashSet<>();
resultTableNames.add(logicTableName + TABLE_SPLIT_SYMBOL + "0");
}
// 샤딩 정보 인쇄
log.info(">>>>>>>>>> INFO범위 슬라이싱, 논리적 테이블:{},물리적 테이블:{}", logicTableName, resultTableNames);
return resultTableNames;
}
@Override
public String getType() {
return null;
}
@Override
public void init() {
}
// --------------------------------------------------------------------------------------------------------------
// 비공개 메서드
// --------------------------------------------------------------------------------------------------------------
/**
* 최소 샤딩 값 가져오기
* @param tableNames 테이블 이름 모음
* @return 최소 샤딩 값
*/
private LocalDateTime getLowerEndpoint(Collection<ShardingRecord> tableNames) {
Optional<LocalDateTime> optional = tableNames.stream()
.map(ShardingRecord::getStartTime)
.min(Comparator.comparing(Function.identity()));
if (optional.isPresent()) {
return optional.get();
} else {
log.error(">>>>>>>>>> ERROR데이터 최소 샤딩 테이블을 가져오지 못했습니다. 나중에 다시 시도하세요. tableName:{}", tableNames);
throw new IllegalArgumentException("데이터 최소 샤딩 테이블을 가져오는 데 실패했습니다. 나중에 다시 시도하세요.");
}
}
/**
* 최대 샤딩 값 가져오기
* @param tableNames 테이블 이름 모음
* @return 최대 샤딩 값
*/
private LocalDateTime getUpperEndpoint(Collection<ShardingRecord> tableNames) {
Optional<LocalDateTime> optional = tableNames.stream()
.map(ShardingRecord::getEndTime)
.max(Comparator.comparing(Function.identity()));
if (optional.isPresent()) {
return optional.get();
} else {
log.error(">>>>>>>>>> ERRORmaxSplitTable 데이터를 가져오지 못했습니다. 나중에 tableName을 다시 시도하세요:{}", tableNames);
throw new IllegalArgumentException("데이터 최대 샤딩 테이블을 가져오는 데 실패했습니다. 나중에 다시 시도하세요.");
}
}
private String getActualTable(ShardingTableCacheEnum logicTable, LocalDateTime dateTime) {
AtomicReference<String> tableName = new AtomicReference<>();
long dateTimeLong = DateUtil.localDateTimeToLong(dateTime);
logicTable.resultTableNamesCache().forEach(shardingRecord -> {
if (DateUtil.localDateTimeToLong(shardingRecord.getStartTime()) <= dateTimeLong &&
DateUtil.localDateTimeToLong(shardingRecord.getEndTime()) >= dateTimeLong){
tableName.set(shardingRecord.getActualTable());
}
});
return tableName.get();
}
private Set<String> getActualTableSet(ShardingTableCacheEnum logicTable, Range<LocalDateTime> valueRange) {
Set<String> tableNameList = new HashSet<>();
// between and 시작 값은
boolean hasLowerBound = valueRange.hasLowerBound();
boolean hasUpperBound = valueRange.hasUpperBound();
// 최대값 및 최소값 가져오기
Set<ShardingRecord> tableNameCache = logicTable.resultTableNamesCache();
LocalDateTime min = hasLowerBound ? valueRange.lowerEndpoint() :getLowerEndpoint(tableNameCache);
LocalDateTime max = hasUpperBound ? valueRange.upperEndpoint() :getUpperEndpoint(tableNameCache);
long minLong = DateUtil.localDateTimeToLong(min);
long maxLong = DateUtil.localDateTimeToLong(max);
logicTable.resultTableNamesCache().forEach(shardingRecord -> {
long startTimeLong = DateUtil.localDateTimeToLong(shardingRecord.getStartTime());
long endTimeLong = DateUtil.localDateTimeToLong(shardingRecord.getEndTime());
if (!(maxLong < startTimeLong || endTimeLong < minLong)){
//
tableNameList.add(shardingRecord.getActualTable());
}
});
return tableNameList;
}
}
커스텀 슬라이싱 알고리즘 툴 클래스
@Slf4j
public class ShardingAlgorithmTool {
private static IShardingRecordService shardingRecordService;
/** 테이블 샤딩 표기법, 예: t_user_202201 샤딩 기호가 "_" */
private static final String TABLE_SPLIT_SYMBOL = "_";
/** 데이터베이스 구성*/
private static final Environment ENV = SpringUtil.getApplicationContext().getEnvironment();
private static final String DATASOURCE_URL = ENV.getProperty("spring.shardingsphere.datasource.mydb.url");
private static final String DATASOURCE_USERNAME = ENV.getProperty("spring.shardingsphere.datasource.mydb.username");
private static final String DATASOURCE_PASSWORD = ENV.getProperty("spring.shardingsphere.datasource.mydb.password");
/**
* 샤딩 관리 서비스 초기화
* @param service
*/
public static void initService(IShardingRecordService service){
shardingRecordService = service;
}
/**
* 모든 캐시 다시 로드
*/
public static void tableNameCacheReloadAll() {
Arrays.stream(ShardingTableCacheEnum.values()).forEach(ShardingAlgorithmTool::tableNameCacheReload);
}
/**
* 지정된 샤딩 캐시를 다시 로드합니다.
* @param logicTable 논리적 테이블, 예: t_user
*/
public static void tableNameCacheReload(ShardingTableCacheEnum logicTable) {
// 데이터베이스의 모든 테이블 이름 읽기
List<ShardingRecord> tableNameList = getAllTableNameBySchema(logicTable);
// 캐시, 구성 업데이트
logicTable.atomicUpdateCacheAndActualDataNodes(tableNameList);
// 이전 캐시 삭제
logicTable.resultTableNamesCache().clear();
// 새 캐시에 쓰기
logicTable.resultTableNamesCache().addAll(tableNameList);
}
/**
* 모든 테이블 이름 가져오기
* @return 테이블 이름 모음
* @param logicTable
*/
public static List<ShardingRecord> getAllTableNameBySchema(ShardingTableCacheEnum logicTable) {
List<ShardingRecord> tableNames = new ArrayList<>();
try {
String logicTableName = logicTable.logicTableName();
tableNames = shardingRecordService.queryAllShardingRecordByLogicName(logicTableName);
} catch (Exception e) {
log.error(">>>>>>>>>> ERROR데이터베이스 연결에 실패했습니다. 나중에 다시 시도하세요, 이유:{}", e.getMessage(), e);
}
return tableNames;
}
/**
* 실제 데이터 노드 구성 동적 업데이트
*
* @param logicTableName 논리적 테이블 이름
* @param tableNamesCache 실제 테이블 이름 수집
*/
public static void actualDataNodesRefresh(String logicTableName, List<ShardingRecord> tableNamesCache) {
try {
if (CollectionUtils.isEmpty(tableNamesCache)){
// 테이블이 없을 때 처음에 초기화 방지
return;
}
// 데이터 샤딩 노드 가져오기
String dbName = "mydb";
log.info(">>>>>>>>>> INFO샤딩 테이블 구성 업데이트,logicTableName:{},tableNamesCache:{}", logicTableName, tableNamesCache);
// generate actualDataNodes
String newActualDataNodes = tableNamesCache.stream().map(ShardingRecord::getActualTable).map(o -> String.format("%s.%s", dbName, o)).collect(Collectors.joining(","));
ShardingSphereDataSource shardingSphereDataSource = SpringUtil.getBean(ShardingSphereDataSource.class);
updateShardRuleActualDataNodes(shardingSphereDataSource, logicTableName, newActualDataNodes);
}catch (Exception e){
log.error("초기화 동적 양식 실패, 이유:{}", e.getMessage(), e);
}
}
// --------------------------------------------------------------------------------------------------------------
// 비공개 메서드
// --------------------------------------------------------------------------------------------------------------
/**
* RefreshActualDataNodes
*/
private static void updateShardRuleActualDataNodes(ShardingSphereDataSource dataSource, String logicTableName, String newActualDataNodes) {
// Context manager.
ContextManager contextManager = dataSource.getContextManager();
// Rule configuration.
String schemaName = "logic_db";
Collection<RuleConfiguration> newRuleConfigList = new LinkedList<>();
Collection<RuleConfiguration> oldRuleConfigList = dataSource.getContextManager()
.getMetaDataContexts()
.getMetaData(schemaName)
.getRuleMetaData()
.getConfigurations();
for (RuleConfiguration oldRuleConfig : oldRuleConfigList) {
if (oldRuleConfig instanceof AlgorithmProvidedShardingRuleConfiguration) {
// Algorithm provided sharding rule configuration
AlgorithmProvidedShardingRuleConfiguration oldAlgorithmConfig = (AlgorithmProvidedShardingRuleConfiguration) oldRuleConfig;
AlgorithmProvidedShardingRuleConfiguration newAlgorithmConfig = new AlgorithmProvidedShardingRuleConfiguration();
// Sharding table rule configuration Collection
Collection<ShardingTableRuleConfiguration> newTableRuleConfigList = new LinkedList<>();
Collection<ShardingTableRuleConfiguration> oldTableRuleConfigList = oldAlgorithmConfig.getTables();
oldTableRuleConfigList.forEach(oldTableRuleConfig -> {
if (logicTableName.equals(oldTableRuleConfig.getLogicTable())) {
ShardingTableRuleConfiguration newTableRuleConfig = new ShardingTableRuleConfiguration(oldTableRuleConfig.getLogicTable(), newActualDataNodes);
newTableRuleConfig.setTableShardingStrategy(oldTableRuleConfig.getTableShardingStrategy());
newTableRuleConfig.setDatabaseShardingStrategy(oldTableRuleConfig.getDatabaseShardingStrategy());
newTableRuleConfig.setKeyGenerateStrategy(oldTableRuleConfig.getKeyGenerateStrategy());
newTableRuleConfigList.add(newTableRuleConfig);
} else {
newTableRuleConfigList.add(oldTableRuleConfig);
}
});
newAlgorithmConfig.setTables(newTableRuleConfigList);
newAlgorithmConfig.setAutoTables(oldAlgorithmConfig.getAutoTables());
newAlgorithmConfig.setBindingTableGroups(oldAlgorithmConfig.getBindingTableGroups());
newAlgorithmConfig.setBroadcastTables(oldAlgorithmConfig.getBroadcastTables());
newAlgorithmConfig.setDefaultDatabaseShardingStrategy(oldAlgorithmConfig.getDefaultDatabaseShardingStrategy());
newAlgorithmConfig.setDefaultTableShardingStrategy(oldAlgorithmConfig.getDefaultTableShardingStrategy());
newAlgorithmConfig.setDefaultKeyGenerateStrategy(oldAlgorithmConfig.getDefaultKeyGenerateStrategy());
newAlgorithmConfig.setDefaultShardingColumn(oldAlgorithmConfig.getDefaultShardingColumn());
newAlgorithmConfig.setShardingAlgorithms(oldAlgorithmConfig.getShardingAlgorithms());
newAlgorithmConfig.setKeyGenerators(oldAlgorithmConfig.getKeyGenerators());
newRuleConfigList.add(newAlgorithmConfig);
}
}
// update context
contextManager.alterRuleConfiguration(schemaName, newRuleConfigList);
}
/**
* 샤딩 테이블 생성
* @param logicTable
* @param tableName 실제 테이블 이름, 예: t_user_1
* @return 생성 결과
*/
public static boolean createShardingTable(ShardingTableCacheEnum logicTable, String tableName, LocalDateTime startTime, LocalDateTime endTime) {
String index = tableName.replace(logicTable.logicTableName() + TABLE_SPLIT_SYMBOL,"");
synchronized (logicTable.logicTableName().intern()) {
// 테이블이 캐시에 없는 경우 테이블을 생성하고 캐시에 추가합니다.
executeSql(Collections.singletonList("CREATE TABLE IF NOT EXISTS `" + tableName + "` LIKE `" + logicTable.logicTableName() + "`;"));
// 레코드 추가
ShardingRecord shardingRecord = new ShardingRecord();
shardingRecord.setLogicTable(logicTable.logicTableName());
shardingRecord.setActualTable(tableName);
shardingRecord.setIndexNum(Long.valueOf(index));
shardingRecord.setStartTime(startTime);
shardingRecord.setEndTime(endTime);
shardingRecordService.insert(shardingRecord);
// 캐시 재로드
tableNameCacheReload(logicTable);
}
return true;
}
/**
* SQL 실행
* @param sqlList SQL
*/
private static void executeSql(List<String> sqlList) {
if (StringUtils.isEmpty(DATASOURCE_URL) || StringUtils.isEmpty(DATASOURCE_USERNAME) || StringUtils.isEmpty(DATASOURCE_PASSWORD)) {
log.error(">>>>>>>>>> ERROR데이터베이스 연결이 잘못 구성되었습니다. 나중에 다시 시도하세요.,URL:{}, username:{}, password:{}", DATASOURCE_URL, DATASOURCE_USERNAME, DATASOURCE_PASSWORD);
throw new IllegalArgumentException("데이터베이스 연결이 잘못 구성되었습니다. 나중에 다시 시도하세요.");
}
try (Connection conn = DriverManager.getConnection(DATASOURCE_URL, DATASOURCE_USERNAME, DATASOURCE_PASSWORD)) {
try (Statement st = conn.createStatement()) {
conn.setAutoCommit(false);
for (String sql : sqlList) {
st.execute(sql);
}
} catch (Exception e) {
conn.rollback();
log.error(">>>>>>>>>> ERROR데이터 테이블 생성 실행에 실패했습니다. 나중에 다시 시도하세요(이유):{}", e.getMessage(), e);
throw new IllegalArgumentException("데이터 테이블 생성 실행에 실패했습니다. 나중에 다시 시도하세요.");
}
} catch (SQLException e) {
log.error(">>>>>>>>>> ERROR데이터베이스 연결에 실패했습니다. 나중에 다시 시도하세요:{}", e.getMessage(), e);
throw new IllegalArgumentException("데이터베이스 연결에 실패했습니다. 나중에 다시 시도하세요.");
}
}
}
하위 테이블에 대한 시간 제한 작업 생성 및 초기화
@Component
@Slf4j
public class TableInitJob {
@Resource
private ConfigProperty configProperty;
private final String TABLE_SPLIT_SYMBOL = "_";
@Resource
private IShardingRecordService shardingRecordService;
@Scheduled(cron = "${sharding.table.init.job:0 0 2 * * ?}")
public void createTableAndDeleteExpiredTable() {
// 향후 테이블 초기화 - 3일
ShardingTableCacheEnum.logicTableNames().forEach(logicTable->{
List<ShardingRecord> shardingRecords = shardingRecordService.queryAllShardingRecordByLogicName(logicTable);
if (CollectionUtils.isEmpty(shardingRecords)){
int index = 1;
// 시작 시간부터 종료 시간까지 거꾸로 생성됨> 현재 시간+ configProperty.shardingTimeDys
LocalDateTime startTime = DateUtil.string2LocalDateTime(configProperty.getShardingStartTime(),null);
LocalDateTime endTime = DateUtil.getEndDateTime(DateUtil.addDays(startTime, configProperty.getShardingTimeDys()));
while (!endTime.isAfter(DateUtil.addDays(LocalDateTime.now(),configProperty.getShardingTimeDys()))){
String tableName = logicTable + TABLE_SPLIT_SYMBOL + index;
ShardingAlgorithmTool.createShardingTable(ShardingTableCacheEnum.of(logicTable),tableName,startTime,endTime);
startTime = DateUtil.addDays(startTime,configProperty.getShardingTimeDys() + 1);
endTime = DateUtil.addDays(endTime,configProperty.getShardingTimeDys() + 1);
index++;
}
}else {
// 마지막 시간부터 종료 시간까지 거꾸로 생성됨> 현재 시간+ configProperty.shardingTimeDys
ShardingRecord shardingRecord = shardingRecords.get(shardingRecords.size() - 1);
int index = shardingRecord.getIndexNum().intValue() + 1;
// 시작 시간부터 종료 시간까지 거꾸로 생성됨> 현재 시간+ configProperty.shardingTimeDys
LocalDateTime startTime = shardingRecord.getStartTime();
LocalDateTime endTime = shardingRecord.getEndTime();
while (!endTime.isAfter(DateUtil.addDays(LocalDateTime.now(),configProperty.getShardingTimeDys()))){
String tableName = logicTable + TABLE_SPLIT_SYMBOL + index;
startTime = DateUtil.addDays(startTime,configProperty.getShardingTimeDys() + 1);
endTime = DateUtil.addDays(endTime,configProperty.getShardingTimeDys() + 1);
ShardingAlgorithmTool.createShardingTable(ShardingTableCacheEnum.of(logicTable),tableName,startTime,endTime);
index++;
}
}
});
}
}




