ShardingJDBC分库分表
一、数据库
1.建立数据库
(1)创建中心库
CREATE DATABASE `ric_center` CHARACTER SET 'utf8mb4';
(2)创建分库
CREATE DATABASE `ric_ch` CHARACTER SET 'utf8mb4';
CREATE DATABASE `ric_hk` CHARACTER SET 'utf8mb4';
CREATE DATABASE `ric_us` CHARACTER SET 'utf8mb4';
2.创建分表模板表
(1)创建中心库表格
CREATE TABLE `code_table` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`symbol` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '股票代码',
`symbol_convert` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '转换后的股票代码',
`market_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '市场代码',
`name_en` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '股票英文名称',
`name_en_convert` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '股票英文转换',
`name_cn` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '股票中文名称',
`name_cn_convert` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '股票中文转换',
`underlying` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标的股份',
`index_underlying` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '指数',
`market_item` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`lot_size` int DEFAULT NULL COMMENT '可出售股票最小数量',
`currency` int DEFAULT NULL COMMENT '股票交易使用的货币类型***的枚举',
`list_market` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`symbol_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '股票类型',
`list_date` date DEFAULT NULL COMMENT '股票上市时间',
`delist_date` date DEFAULT NULL COMMENT '股票退市时间',
`amt_os` bigint DEFAULT NULL COMMENT '流通股本,单位1',
`amt_os_uns` bigint DEFAULT NULL COMMENT '总股本(股票发行总量),单位1',
`refresh_time` bigint DEFAULT NULL COMMENT '操作刷新时间',
`created_time` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`created_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`updated_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_unique_symbol_code_table_index` (`symbol`) USING BTREE COMMENT '股票代码索引',
KEY `idx_unique_symbol_convert_code_table_index` (`symbol_convert`) USING BTREE COMMENT '转换后的股票代码的唯一索引'
) ENGINE=InnoDB AUTO_INCREMENT=114556 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
(2)创建分库的模板表格
- 创建模板表格,生成后的表格类型为“trade_record_250303_0”和 kline_D_0 ~ 15、kline_M_0 ~ 15等。
CREATE TABLE `kline` (
`id` bigint NOT NULL AUTO_INCREMENT,
`symbol` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`symbol_id` bigint NOT NULL,
`kline_type` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`time` bigint NOT NULL,
`market_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`trade_date` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`open` decimal(20,4) NOT NULL,
`high` decimal(20,4) NOT NULL,
`low` decimal(20,4) NOT NULL,
`close` decimal(20,4) NOT NULL,
`vwap` decimal(20,4) NOT NULL,
`volume` decimal(20,4) NOT NULL,
`amount` decimal(20,4) NOT NULL,
`count` int NOT NULL,
`session_id` int NOT NULL DEFAULT '1' COMMENT '-1 - 盘前;1 - 盘中;-2 - 盘后',
`created_time` datetime DEFAULT NULL,
`updated_time` datetime DEFAULT NULL,
`created_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`updated_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_symbol` (`symbol`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='k线表';
CREATE TABLE `trade_record` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`symbol` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '股票编码',
`symbol_id` bigint NOT NULL COMMENT '股票ID',
`market_code` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '股票类型代码',
`trade_date` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '交易日期',
`time` bigint NOT NULL COMMENT '成交时间(utc)',
`price` decimal(24,8) NOT NULL COMMENT '成交价',
`volume` decimal(24,8) NOT NULL COMMENT '单笔成交量',
`amount` decimal(24,8) NOT NULL COMMENT '成交额',
`session_id` tinyint NOT NULL COMMENT '时间类型:-1 - 盘前;1 - 盘中;-2 - 盘后',
`direction` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '-' COMMENT '成交方向:B - 买入;S - 卖出;',
`trade_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '交易ID',
`acc_volume` decimal(24,8) DEFAULT NULL COMMENT '当前总成交(应该是指当天总成交股数)',
`acc_amount` decimal(24,8) DEFAULT NULL COMMENT '当天累计成交额',
`vwap` decimal(24,8) DEFAULT NULL COMMENT '今日加权平均价',
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_trade_record_symbol_time` (`symbol`,`time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='逐笔成交记录表';
DROP PROCEDURE IF EXISTS `CreateKlineTables`;
delimiter ;;
CREATE PROCEDURE `CreateKlineTables`()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE j INT DEFAULT 0;
DECLARE table_name VARCHAR(64);
DECLARE date_parts TEXT;
DECLARE date_part VARCHAR(10);
SET date_parts = 'M5,M30,M60,D,W,M,Y';
WHILE j < LENGTH(date_parts) - LENGTH(REPLACE(date_parts, ',', '')) + 1 DO
SET date_part = SUBSTRING_INDEX(SUBSTRING_INDEX(date_parts, ',', j + 1), ',', -1);
SET i = 0;
WHILE i < 16 DO
SET table_name = CONCAT('kline_', date_part, '_', i);
SET @sql = CONCAT('
CREATE TABLE IF NOT EXISTS ', table_name, ' LIKE kline');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET i = i + 1;
END WHILE;
SET j = j + 1;
END WHILE;
END
;;
delimiter ;
DROP PROCEDURE IF EXISTS `CreateTradeRecordTables`;
delimiter ;;
CREATE PROCEDURE `CreateTradeRecordTables`(IN date_part VARCHAR(10))
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE table_name VARCHAR(64);
WHILE i < 250 DO
SET table_name = CONCAT('trade_record_', date_part, '_', i);
SET @sql = CONCAT('
CREATE TABLE IF NOT EXISTS ', table_name, ' like trade_record');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET i = i + 1;
END WHILE;
END
;;
delimiter ;
DROP PROCEDURE IF EXISTS `DropTradeRecordTables`;
delimiter ;;
CREATE PROCEDURE `DropTradeRecordTables`(IN date_part VARCHAR(10))
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE table_name VARCHAR(64);
WHILE i < 250 DO
SET table_name = CONCAT('trade_record_', date_part, '_', i);
SET @sql = CONCAT('DROP TABLE IF EXISTS ', table_name);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET i = i + 1;
END WHILE;
END
;;
delimiter ;
SET FOREIGN_KEY_CHECKS = 1;
二、代码实现
1.Maven 引用
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zzc.sharding</groupId>
<artifactId>mysql-sharding</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>shardingjdbc</artifactId>
<packaging>jar</packaging>
<name>sharding-jdbc</name>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<mainClass>com.zzc.sharding.ShardingApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**.*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
2.SpringBoot配置
spring:
profiles:
active: db
server:
port: 8888
tomcat:
uri-encoding: UTF-8
max-http-form-post-size: 20MB
mybatis:
mapper-locations: classpath:com/zzc/sharding/dao/**/*.xml
type-aliases-package: com.zzc.sharding.entity
- 创建application-dev.yml,配置分库分表
spring:
shardingsphere:
datasource:
names: center, ds0, ds1, ds2
mapper-locations: com/zzc/sharding/dao/mapper/*.xml
type-aliases-package: com.zzc.sharding.entity
center:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.0.103:3306/ric_center?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: root
ds0:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.0.103:3306/ric_hk?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: root
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.0.103:3306/ric_ch?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: root
ds2:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://192.168.0.103:3306/ric_us?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: root
props:
sql:
show: true
sharding:
default-data-source-name: center
tables:
trade_record:
actual-data-nodes: ds$->{0..2}.trade_record_$->{0..10}
database-strategy:
standard:
sharding-column: market_code
precise-algorithm-class-name: com.zzc.sharding.config.sharding.DbShardingByMarketTypeAlgorithm
table-strategy:
complex:
sharding-columns: trade_date,symbol
algorithm-class-name: com.zzc.sharding.config.sharding.TableShardingByDateAndSymbolAlgorithm
kline_m1:
actual-data-nodes: ds$->{0..2}.kline_m1
database-strategy:
standard:
sharding-column: market_code
precise-algorithm-class-name: com.zzc.sharding.config.sharding.DbShardingByMarketTypeAlgorithm
table-strategy:
complex:
sharding-columns: trade_date
algorithm-class-name: com.zzc.sharding.config.sharding.TableShardingByDateAlg
kline:
actual-data-nodes: ds$->{0..2}.kline_${['M5', 'M30','M60','D','W','M','Y']}_${0..15}
database-strategy:
standard:
sharding-column: market_code
precise-algorithm-class-name: com.zzc.sharding.config.sharding.DbShardingByMarketTypeAlgorithm
table-strategy:
complex:
sharding-columns: kline_type,symbol
algorithm-class-name: com.zzc.sharding.config.sharding.TableShardingByKlineTypeAndSymbolIdAlg
db-sharding:
centerDs: 'center'
tables:
trade_record:
templateTable: 'trade_record'
tableShardingNum: 250
keepDays: 7
clearOffset: 15
ds: 'shardingDataSource'
kline:
templateTable: 'kline'
tableShardingNum: 16
keepDays: 30
clearOffset: 40
ds: 'shardingDataSource'
runCreateJob: false
marketConfigs:
ds0: 'HK, HK_WRNT, HK_BONDA, HK_TRUST'
ds1: 'SH, SZ, SZ_INDEX, SZ_FUND, SZ_GEM'
ds2: 'US, US_PINK, US_OPTION, US_ETF'
3.项目目录结构预览

4.代码编写
(1)config添加
package com.zzc.sharding.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class SpringBeansUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ac) throws BeansException {
applicationContext = ac;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> beanClass) {
return (T) applicationContext.getBean(beanClass);
}
}
package com.zzc.sharding.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
@Slf4j
public class YamlPropertySourceFactory implements PropertySourceFactory {
private static final boolean NEW_YAML_FACTORY = BooleanUtils.toBoolean(System.getenv("NEW_YAML_FACTORY"));
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
try {
if (NEW_YAML_FACTORY) {
return v1(encodedResource);
}
return v0(encodedResource);
} catch (Throwable e) {
if (e.getCause() instanceof FileNotFoundException) {
log.warn("yaml file [{}] not found in local", encodedResource);
throw (FileNotFoundException) e.getCause();
}
if (e instanceof YAMLException || e.getCause() instanceof YAMLException) {
log.error("yaml file [{}] load error", encodedResource);
}
throw e;
}
}
private PropertySource<?> v0(EncodedResource encodedResource) {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
protected PropertySource<?> v1(EncodedResource encodedResource) throws IOException {
return new YamlPropertySourceLoader()
.load(encodedResource.getResource().getFilename(), encodedResource.getResource())
.get(0);
}
}
- DatabaseShardingConfig 加载分库分表相关的配置
package com.zzc.sharding.config.sharding;
import com.zzc.sharding.config.YamlPropertySourceFactory;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "db-sharding")
@PropertySource(value = "classpath:db-sharding.yaml", factory = YamlPropertySourceFactory.class)
public class DatabaseShardingConfig {
private String centerDs;
private Map<String, TableShardingConfig> tables;
private Map<String, String> marketConfigs;
@Setter(AccessLevel.PRIVATE)
private Map<String, String> dbMap;
@PostConstruct
public void init() {
if (marketConfigs == null || marketConfigs.isEmpty()) {
throw new RuntimeException("DatabaseShardingConfig error. configs is empty");
}
Map<String, String> tmp = new HashMap<>();
marketConfigs.forEach((dbName, markets) -> {
for (String market : markets.split(",")) {
tmp.put(market.trim(), dbName);
}
});
dbMap = tmp;
log.info("DatabaseShardingConfig init success. config: [{}]", this);
}
public String getDbName(String market) {
return dbMap.get(market);
}
public TableShardingConfig getTableShardingConfig(String tableName) {
return tables.get(tableName);
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class TableShardingConfig {
private String templateTable;
private int tableShardingNum;
private int keepDays;
private int clearOffset;
private String ds;
private Boolean runCreateJob = true;
}
}
- 分库逻辑DbShardingByMarketTypeAlgorithm,根据DatabaseShardingConfig上述配置的“marketConfigs”中的枚举,匹配不同的数据库
package com.zzc.sharding.config.sharding;
import com.zzc.sharding.config.SpringBeansUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.util.Collection;
@Slf4j
public class DbShardingByMarketTypeAlgorithm implements PreciseShardingAlgorithm<String> {
private DatabaseShardingConfig config;
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
String marketType = preciseShardingValue.getValue();
if (config == null) {
config = SpringBeansUtil.getBean(DatabaseShardingConfig.class);
}
String dbName = config.getDbName(marketType);
if (!collection.contains(dbName)) {
log.error("Database sharding error. column-value : [{}], DatabaseShardingConfig dbName : [{}], shardingsphere configs : [{}]", marketType, dbName, collection);
throw new IllegalArgumentException("Database sharding error.");
}
return dbName;
}
}
- 分表逻辑TableShardingByDateAlg,只按照日期进行分表
package com.zzc.sharding.config.sharding;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@Slf4j
public class TableShardingByDateAlg implements ComplexKeysShardingAlgorithm {
@Override
public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
String date = ((List<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("trade_date")).get(0);
String logicTable = complexKeysShardingValue.getLogicTableName();
return Collections.singletonList(logicTable
+ "_" + date.substring(2).replaceAll("-", ""));
}
}
- 分表逻辑TableShardingByDateAndSymbolAlgorithm,按照日期和symbol进行分表
package com.zzc.sharding.config.sharding;
import com.zzc.sharding.config.SpringBeansUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@Slf4j
public class TableShardingByDateAndSymbolAlgorithm implements ComplexKeysShardingAlgorithm {
private static final String FIELD_NAME_DATE = "trade_date";
private static final String FIELD_NAME_SYMBOL = "symbol";
private DatabaseShardingConfig config;
@Override
public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
if (config == null) {
config = SpringBeansUtil.getBean(DatabaseShardingConfig.class);
}
String date = ((List<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get(FIELD_NAME_DATE)).get(0);
String symbol = ((List<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get(FIELD_NAME_SYMBOL)).get(0);
String logicTable = complexKeysShardingValue.getLogicTableName();
DatabaseShardingConfig.TableShardingConfig shardingConfig = config.getTableShardingConfig(logicTable);
return Collections.singletonList(logicTable + "_" + date.substring(2).replaceAll("-", "") + "_" + getTableSuffix(symbol, shardingConfig.getTableShardingNum()));
}
private static int getTableSuffix(String symbol, int size) {
int h;
return ((symbol == null) ? 0 : (h = symbol.hashCode()) ^ (h >>> 16)) & (size - 1);
}
}
- 分表逻辑TableShardingByKlineTypeAndSymbolIdAlg,按照枚举类型进行分表
package com.zzc.sharding.config.sharding;
import com.zzc.sharding.config.SpringBeansUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@Slf4j
public class TableShardingByKlineTypeAndSymbolIdAlg implements ComplexKeysShardingAlgorithm {
private DatabaseShardingConfig config;
@Override
public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
if (config == null) {
config = SpringBeansUtil.getBean(DatabaseShardingConfig.class);
}
String klineType = ((List<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("kline_type")).get(0);
String symbol = ((List<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("symbol")).get(0);
String logicTable = complexKeysShardingValue.getLogicTableName();
DatabaseShardingConfig.TableShardingConfig shardingConfig = config.getTableShardingConfig(logicTable);
return Collections.singletonList(logicTable
+ "_" + klineType + "_" + getTableSuffix(symbol, shardingConfig.getTableShardingNum()));
}
private static int getTableSuffix(String symbol, int size) {
int h;
return ((symbol == null) ? 0 : (h = symbol.hashCode()) ^ (h >>> 16)) & (size - 1);
}
}
(2)创建定时任务,用于生成数据库表格
package com.zzc.sharding.schedule;
import com.zzc.sharding.config.sharding.DatabaseShardingConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor
public class QuotationDataManagementJob {
private final static int LOCK_WAIT_SECONDS = 10;
private final static int LOCK_LEASE_SECONDS = 30 * 60;
private final static String SHARDING_TABLE_CREATE_SQL = "CREATE TABLE IF NOT EXISTS %s LIKE %s;";
private final static String SHARDING_TABLE_CLEAR_SQL = "DROP TABLE IF EXISTS %s;";
private final static String DS_SHARDING = "shardingDataSource";
private final static String DS_OLAP = "olapDataSource";
private final DatabaseShardingConfig dbShardingConfig;
private final DataSource shardingDataSource;
@Scheduled(cron = "0 8 23 ? * *")
public void createShardingTableJob() {
dbShardingConfig.getTables().forEach((tableName, config) -> {
if(config.getRunCreateJob())
createShardingTable(tableName, config);
});
log.info("createShardingTable job done");
}
@Scheduled(cron = "0 0 10 * * ?")
public void clearShardingTableJob() {
dbShardingConfig.getTables().forEach((tableName, config) -> {
clearShardingTable(tableName, config);
});
log.info("clearShardingTable job done");
}
private void createShardingTable(String tableName, DatabaseShardingConfig.TableShardingConfig config) {
((ShardingDataSource) shardingDataSource).getDataSourceMap().forEach((dbName, myDataSource) -> {
if (dbName.equals(dbShardingConfig.getCenterDs())) {
return;
}
try {
Connection connection = myDataSource.getConnection();
List<String> nextWeekWorkDays = getNextWeekWorkDays();
nextWeekWorkDays.forEach(day -> {
createShardingTable(dbName, connection, tableName, day, config);
});
} catch (Throwable t) {
log.error("createShardingTable error. db : [{}] tableName : [{}]", dbName, tableName, t);
}
});
}
private void createShardingTable(String dbName, Connection connection, String tableName, String day, DatabaseShardingConfig.TableShardingConfig config) {
DatabaseShardingConfig.TableShardingConfig tableShardingConfig = dbShardingConfig.getTableShardingConfig(tableName);
if (config.getTableShardingNum() > 1) {
for (int i = 0; i < tableShardingConfig.getTableShardingNum(); i++) {
String realTableName = tableName + "_" + day.substring(2) + "_" + i;
try {
String sql = String.format(SHARDING_TABLE_CREATE_SQL, realTableName, tableShardingConfig.getTemplateTable());
connection.createStatement().execute(sql);
log.info("createShardingTable success. db : [{}] tableName : [{}], realTableName : [{}], sql : [{}]", dbName, tableName, realTableName, sql);
} catch (Throwable t) {
log.error("createShardingTable error. db : [{}] tableName : [{}], realTableName : [{}]", dbName, tableName, realTableName, t);
}
}
} else {
String realTableName = tableName + "_" + day.substring(2);
try {
String sql = String.format(SHARDING_TABLE_CREATE_SQL, realTableName, tableShardingConfig.getTemplateTable());
connection.createStatement().execute(sql);
log.info("createShardingTable success. db : [{}] tableName : [{}], realTableName : [{}], sql : [{}]", dbName, tableName, realTableName, sql);
} catch (Throwable t) {
log.error("createShardingTable error. db : [{}] tableName : [{}], realTableName : [{}]", dbName, tableName, realTableName, t);
}
}
}
private List<String> getNextWeekWorkDays() {
LocalDate today = LocalDate.now();
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
List<String> workDays = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
for (int i = 0; i < 5; i++) {
LocalDate date = nextMonday.plusDays(i);
workDays.add(date.format(formatter));
}
return workDays;
}
private void clearShardingTable(String tableName, DatabaseShardingConfig.TableShardingConfig config) {
((ShardingDataSource) shardingDataSource).getDataSourceMap().forEach((dbName, myDataSource) -> {
if (dbName.equals(dbShardingConfig.getCenterDs())) {
return;
}
try {
Connection connection = myDataSource.getConnection();
List<String> nextWeekWorkDays = getToBeClearDays(tableName);
nextWeekWorkDays.forEach(day -> {
clearShardingTable(dbName, connection, tableName, day, config);
});
} catch (Throwable t) {
log.error("clearShardingTable error. db : [{}] tableName : [{}]", dbName, tableName, t);
}
});
}
private void clearShardingTable(String dbName, Connection connection, String tableName, String day, DatabaseShardingConfig.TableShardingConfig config) {
if (config.getTableShardingNum() > 1) {
for (int i = 0; i < config.getTableShardingNum(); i++) {
String realTableName = tableName + "_" + day.substring(2) + "_" + i;
try {
String sql = String.format(SHARDING_TABLE_CLEAR_SQL, realTableName);
connection.createStatement().execute(sql);
log.info("clearShardingTable success. db : [{}] tableName : [{}], realTableName : [{}], sql : [{}]", dbName, tableName, realTableName, sql);
} catch (Throwable t) {
log.error("clearShardingTable error. db : [{}] tableName : [{}], realTableName : [{}]", dbName, tableName, realTableName, t);
}
}
} else {
String realTableName = tableName + "_" + day.substring(2);
try {
String sql = String.format(SHARDING_TABLE_CLEAR_SQL, realTableName);
connection.createStatement().execute(sql);
log.info("clearShardingTable success. db : [{}] tableName : [{}], realTableName : [{}], sql : [{}]", dbName, tableName, realTableName, sql);
} catch (Throwable t) {
log.error("clearShardingTable error. db : [{}] tableName : [{}], realTableName : [{}]", dbName, tableName, realTableName, t);
}
}
}
private List<String> getToBeClearDays(String tableName) {
List<String> days = new ArrayList<>();
DatabaseShardingConfig.TableShardingConfig tableShardingConfig = dbShardingConfig.getTableShardingConfig(tableName);
LocalDate today = LocalDate.now();
LocalDate startDay = today.minusDays(tableShardingConfig.getClearOffset());
LocalDate endDay = today.minusDays(tableShardingConfig.getKeepDays());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
for (LocalDate date = startDay; date.isBefore(endDay); date = date.plusDays(1)) {
days.add(date.format(formatter));
}
return days;
}
}
(3)ORM层
中心库
CodeTable
package com.zzc.sharding.entity.center;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class CodeTable implements Serializable {
private Long id;
private String symbol;
private String symbolConvert;
private String nameEn;
private String nameEnConvert;
private String nameCn;
private String nameCnConvert;
private String underlying;
private String indexUnderlying;
private Integer lotSize;
private Integer currency;
private String marketCode;
private String marketItem;
private String listMarket;
private String symbolType;
private Date listDate;
private Date delistDate;
private BigDecimal amtOs;
private BigDecimal amtOsUns;
private Long refreshTime;
private Date createdTime;
private Date updatedTime;
private String createdBy;
private String updatedBy;
}
package com.zzc.sharding.dao.center;
import com.zzc.sharding.entity.center.CodeTable;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface CodeTableDao {
void insert(CodeTable codeTable);
CodeTable selectBySymbol(@Param("symbol") String symbol);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzc.sharding.dao.center.CodeTableDao">
<resultMap type="com.zzc.sharding.entity.center.CodeTable" id="codeTableMap">
<result property="id" column="id"/>
<result property="symbol" column="symbol"/>
<result property="symbolConvert" column="symbol_convert"/>
<result property="marketCode" column="market_code"/>
<result property="nameEn" column="name_en"/>
<result property="nameEnConvert" column="name_en_convert"/>
<result property="nameCn" column="name_cn"/>
<result property="nameCnConvert" column="name_cn_convert"/>
<result property="underlying" column="underlying"/>
<result property="indexUnderlying" column="index_underlying"/>
<result property="marketItem" column="market_item"/>
<result property="lotSize" column="lot_size"/>
<result property="currency" column="currency"/>
<result property="listMarket" column="list_market"/>
<result property="symbolType" column="symbol_type"/>
<result property="listDate" column="list_date"/>
<result property="delistDate" column="delist_date"/>
<result property="amtOs" column="amt_os"/>
<result property="amtOsUns" column="amt_os_uns"/>
<result property="refreshTime" column="refresh_time"/>
<result property="createdTime" column="created_time"/>
<result property="updatedTime" column="updated_time"/>
<result property="createdBy" column="created_by"/>
<result property="updatedBy" column="updated_by"/>
</resultMap>
<sql id="column">
id,
symbol,
symbol_convert,
market_code,
name_en,
name_en_convert,
name_cn,
name_cn_convert,
underlying,
index_underlying,
market_item,
lot_size,
currency,
list_market,
symbol_type,
list_date,
delist_date,
amt_os,
amt_os_uns,
refresh_time,
created_time,
updated_time,
created_by,
updated_by
</sql>
<insert id="insert" parameterType="com.zzc.sharding.entity.center.CodeTable">
INSERT INTO code_table
(
id,
symbol,
symbol_convert,
market_code,
name_en,
name_en_convert,
name_cn,
name_cn_convert,
underlying,
index_underlying,
market_item,
lot_size,
currency,
list_market,
symbol_type,
list_date,
delist_date,
amt_os,
amt_os_uns,
refresh_time,
created_by
)
VALUES
(
#{id},
#{symbol},
#{symbolConvert},
#{marketCode},
#{nameEn},
#{nameEnConvert},
#{nameCn},
#{nameCnConvert},
#{underlying},
#{indexUnderlying},
#{marketItem},
#{lotSize},
#{currency},
#{listMarket},
#{symbolType},
#{listDate},
#{delistDate},
#{amtOs},
#{amtOsUns},
#{refreshTime},
#{createdBy}
)
</insert>
<select id="selectBySymbol" resultMap="codeTableMap">
SELECT
<include refid="column"/>
FROM code_table
WHERE
symbol = #{symbol}
</select>
</mapper>
BrokerTable
package com.zzc.sharding.entity.center;
import java.util.Date;
public class BrokerTable {
private Long id;
private Long excelId;
private String brokerNo;
private String nameEn;
private String nameEnConvert;
private String nameCn;
private String nameCnConvert;
private String status;
private String address1;
private String address2;
private String address3;
private String address4;
private String addressCn;
private String phone;
private String fax;
private String websiteAddress;
private String stockOptions;
private Date createdTime;
private Date updatedTime;
private String createdBy;
private String updatedBy;
}
package com.zzc.sharding.dao.center;
import com.zzc.sharding.entity.center.BrokerTable;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface BrokerTableDao {
void insert(BrokerTable brokerTable);
BrokerTable selectByBrokerNo(@Param("brokerNo") String brokerNo);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzc.sharding.dao.center.BrokerTableDao">
<resultMap type="com.zzc.sharding.entity.center.BrokerTable" id="brokerTableMap">
<result property="id" column="id"/>
<result property="excelId" column="excel_id"/>
<result property="brokerNo" column="broker_no"/>
<result property="nameEn" column="name_en"/>
<result property="nameEnConvert" column="name_en_convert"/>
<result property="nameCn" column="name_cn"/>
<result property="nameCnConvert" column="name_cn_convert"/>
<result property="status" column="status"/>
<result property="address1" column="address1"/>
<result property="address2" column="address2"/>
<result property="address3" column="address3"/>
<result property="address4" column="address4"/>
<result property="addressCn" column="address_cn"/>
<result property="phone" column="phone"/>
<result property="fax" column="fax"/>
<result property="websiteAddress" column="website_address"/>
<result property="stockOptions" column="stock_options"/>
<result property="createdTime" column="created_time"/>
<result property="updatedTime" column="updated_time"/>
<result property="createdBy" column="created_by"/>
<result property="updatedBy" column="updated_by"/>
</resultMap>
<sql id="column">
id,
excel_id,
broker_no,
name_en,
name_en_convert,
name_cn,
name_cn_convert,
status,
address1,
address2,
address3,
address4,
address_cn,
phone,
fax,
website_address,
stock_options,
created_time,
updated_time,
created_by,
updated_by
</sql>
<insert id="insert" parameterType="com.zzc.sharding.entity.center.BrokerTable">
INSERT INTO broker_table
(
<include refid="column"/>
)
VALUES
(
#{id},
#{excelId},
#{brokerNo},
#{nameEn},
#{nameEnConvert},
#{nameCn},
#{nameCnConvert},
#{status},
#{address1},
#{address2},
#{address3},
#{address4},
#{addressCn},
#{phone},
#{fax},
#{websiteAddress},
#{stockOptions},
#{createdTime},
#{updatedTime},
#{createdBy},
#{updatedBy}
)
</insert>
<select id="selectByBrokerNo" resultMap="brokerTableMap">
SELECT
<include refid="column"/>
FROM broker_table
WHERE
broker_no = #{brokerNo}
</select>
</mapper>
分库分表
TradeRecord
package com.zzc.sharding.entity.sharding;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TradeRecord {
private Long id;
private String symbol;
private Long symbolId;
private String marketCode;
private String tradeDate;
private Long time;
private BigDecimal price;
private BigDecimal volume;
private BigDecimal amount;
private Integer sessionId;
private String direction;
private String tradeId;
private BigDecimal accVolume;
private BigDecimal accAmount;
private BigDecimal vwap;
private Date createdTime;
private Date updatedTime;
private String createdBy;
private String updatedBy;
}
package com.zzc.sharding.dao.sharding;
import com.zzc.sharding.entity.sharding.TradeRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
@Mapper
public interface TradeRecordDao {
void insert(TradeRecord tradeRecord);
List<TradeRecord> selectBySymbolWithTime(@Param("marketCode") String marketCode, @Param("symbol") String symbol, @Param("tradeDate") String tradeDate);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzc.sharding.dao.sharding.TradeRecordDao">
<resultMap type="com.zzc.sharding.entity.sharding.TradeRecord" id="tradeRecordMap">
<result property="id" column="id"/>
<result property="symbol" column="symbol"/>
<result property="symbolId" column="symbol_id"/>
<result property="marketCode" column="market_code"/>
<result property="tradeDate" column="trade_date"/>
<result property="time" column="time"/>
<result property="price" column="price"/>
<result property="volume" column="volume"/>
<result property="amount" column="amount"/>
<result property="sessionId" column="session_id"/>
<result property="direction" column="direction"/>
<result property="tradeId" column="trade_id"/>
<result property="accVolume" column="acc_volume"/>
<result property="accAmount" column="acc_amount"/>
<result property="vwap" column="vwap"/>
<result property="createdTime" column="created_time"/>
<result property="updatedTime" column="updated_time"/>
<result property="createdBy" column="created_by"/>
<result property="updatedBy" column="updated_by"/>
</resultMap>
<sql id="column">
id,
symbol,
symbol_id,
market_code,
trade_date,
time,
price,
volume,
amount,
session_id,
direction,
trade_id,
acc_volume,
acc_amount,
vwap,
created_time,
updated_time
</sql>
<insert id="insert" parameterType="com.zzc.sharding.entity.sharding.TradeRecord">
INSERT INTO trade_record
(
<include refid="column"/>
)
VALUES
(
#{id},
#{symbol},
#{symbolId},
#{marketCode},
#{tradeDate},
#{time},
#{price},
#{volume},
#{amount},
#{sessionId},
#{direction},
#{tradeId},
#{accVolume},
#{accAmount},
#{vwap},
#{createdTime},
#{updatedTime}
)
</insert>
<select id="selectBySymbolWithTime" resultMap="tradeRecordMap">
SELECT
<include refid="column"/>
FROM trade_record
WHERE
market_code = #{marketCode}
AND symbol = #{symbol}
AND trade_date = #{tradeDate}
</select>
</mapper>
Kline
package com.zzc.sharding.entity.sharding;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Kline {
private Long id;
private String symbol;
private Long symbolId;
private String klineType;
private String marketCode;
private String tradeDate;
private BigDecimal open;
private BigDecimal high;
private BigDecimal low;
private BigDecimal close;
private BigDecimal vwap;
private BigDecimal volume;
private BigDecimal amount;
private long time;
private int count;
private Integer sessionId;
private String date;
private Date createdTime;
private Date updatedTime;
private String createdBy;
private String updatedBy;
}
package com.zzc.sharding.dao.sharding;
import com.zzc.sharding.entity.sharding.Kline;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface KlineDao {
void insert(Kline kline);
List<Kline> selectBySymbolWithTime(@Param("marketCode") String marketCode, @Param("symbol") String symbol, @Param("klineType") String klineType);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzc.sharding.dao.sharding.KlineDao">
<resultMap type="com.zzc.sharding.entity.sharding.Kline" id="klineMap">
<result property="id" column="id"/>
<result property="symbol" column="symbol"/>
<result property="symbolId" column="symbol_id"/>
<result property="klineType" column="kline_type"/>
<result property="time" column="time"/>
<result property="marketCode" column="market_code"/>
<result property="tradeDate" column="trade_date"/>
<result property="open" column="open"/>
<result property="high" column="high"/>
<result property="low" column="low"/>
<result property="close" column="close"/>
<result property="vwap" column="vwap"/>
<result property="volume" column="volume"/>
<result property="amount" column="amount"/>
<result property="count" column="count"/>
<result property="sessionId" column="session_id"/>
</resultMap>
<sql id="column">
id,
symbol,
symbol_id,
kline_type,
time,
market_code,
trade_date,
open,
high,
low,
close,
vwap,
volume,
amount,
count,
session_id
</sql>
<insert id="insert" parameterType="com.zzc.sharding.entity.sharding.Kline">
INSERT INTO kline
(
<include refid="column"/>
)
VALUES
(
#{id},
#{symbol},
#{symbolId},
#{klineType},
#{time},
#{marketCode},
#{tradeDate},
#{open},
#{high},
#{low},
#{close},
#{vwap},
#{volume},
#{amount},
#{count},
#{sessionId}
)
</insert>
<select id="selectBySymbolWithTime" resultMap="klineMap">
SELECT
<include refid="column"/>
FROM kline
WHERE
market_code = #{marketCode}
AND symbol = #{symbol}
AND kline_type = #{klineType}
</select>
</mapper>
KlineM1
package com.zzc.sharding.entity.sharding;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class KlineM1 {
private Long id;
private String symbol;
private Long symbolId;
private String marketCode;
private String tradeDate;
private BigDecimal open;
private BigDecimal high;
private BigDecimal low;
private BigDecimal close;
private BigDecimal vwap;
private BigDecimal volume;
private BigDecimal amount;
private long time;
private int count;
private Integer sessionId;
private String date;
private Date createdTime;
private Date updatedTime;
private String createdBy;
private String updatedBy;
}
(4)测试部分代码
CodeTable验证中心库
package com.zzc.sharding.service;
import com.zzc.sharding.entity.center.CodeTable;
public interface CodeTableService {
void addCode();
CodeTable getCodeBy(String symbol);
}
package com.zzc.sharding.service.Impl;
import com.zzc.sharding.dao.center.CodeTableDao;
import com.zzc.sharding.entity.center.CodeTable;
import com.zzc.sharding.service.CodeTableService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class CodeTableServiceImpl implements CodeTableService {
private final CodeTableDao codeTableDao;
@Override
public void addCode() {
CodeTable codeTable = new CodeTable();
codeTable.setMarketCode("HK");
codeTable.setSymbol("00070.HK");
codeTable.setSymbolConvert("00070.HK");
codeTable.setNameCn("腾讯控股");
codeTable.setNameCnConvert("腾讯控股");
codeTable.setNameEn("Tencent");
codeTable.setNameEnConvert("Tencent");
codeTable.setRefreshTime(System.currentTimeMillis());
codeTableDao.insert(codeTable);
}
@Override
public CodeTable getCodeBy(String symbol) {
return codeTableDao.selectBySymbol(symbol);
}
}
package com.zzc.sharding.controller;
import com.zzc.sharding.entity.center.CodeTable;
import com.zzc.sharding.service.CodeTableService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/v1/code/")
@RequiredArgsConstructor
public class CodeTableController {
private final CodeTableService codeTableService;
@RequestMapping(value = "add")
public String add() {
codeTableService.addCode();
return "success";
}
@RequestMapping(value = "get")
public CodeTable getCodeTable(String symbol) {
return codeTableService.getCodeBy(symbol);
}
}
TradeRecord验证时间类型分库分表
package com.zzc.sharding.service;
import com.zzc.sharding.entity.sharding.TradeRecord;
import java.util.List;
public interface TradeRecordService {
void addTradeRecord(TradeRecord tradeRecord);
List<TradeRecord> getTradeRecords(String market, String symbol, String tradeDate);
}
package com.zzc.sharding.service.Impl;
import com.zzc.sharding.dao.sharding.TradeRecordDao;
import com.zzc.sharding.entity.sharding.TradeRecord;
import com.zzc.sharding.service.TradeRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class TradeRecordServiceImpl implements TradeRecordService {
private final TradeRecordDao tradeRecordDao;
@Override
public void addTradeRecord(TradeRecord tradeRecord) {
TradeRecord record = new TradeRecord();
record.setId(System.currentTimeMillis());
record.setMarketCode("HK");
record.setSymbol("00070.HK");
record.setSymbolId(114554L);
record.setTradeDate("2025-02-24");
record.setTime(System.currentTimeMillis());
record.setPrice(new BigDecimal("0.01"));
record.setVolume(new BigDecimal("0.01"));
record.setAmount(new BigDecimal("1"));
record.setSessionId(1);
record.setDirection("B");
record.setTradeId(System.currentTimeMillis() + "");
record.setCreatedTime(new Date());
record.setUpdatedTime(new Date());
tradeRecordDao.insert(record);
}
@Override
public List<TradeRecord> getTradeRecords(String market, String symbol, String tradeDate) {
return tradeRecordDao.selectBySymbolWithTime(market, symbol, tradeDate);
}
}
package com.zzc.sharding.controller;
import com.zzc.sharding.entity.sharding.TradeRecord;
import com.zzc.sharding.service.TradeRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping(value = "/v1/trade/")
@RequiredArgsConstructor
public class TradeRecordController {
private final TradeRecordService tradeRecordService;
@RequestMapping(value = "add")
public Object addTradeRecord(TradeRecord tradeRecord) {
tradeRecordService.addTradeRecord(tradeRecord);
return "success";
}
@RequestMapping(value = "get")
public Object addTradeRecord() {
return tradeRecordService.getTradeRecords("HK", "00070.HK", "2025-02-24");
}
}
Kline验证枚举类型分库分表
package com.zzc.sharding.service;
import com.zzc.sharding.entity.sharding.Kline;
import java.util.List;
public interface KlineService {
void addKine(Kline kline);
List<Kline> getKine();
}
package com.zzc.sharding.service.Impl;
import com.zzc.sharding.dao.sharding.KlineDao;
import com.zzc.sharding.entity.sharding.Kline;
import com.zzc.sharding.service.KlineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class KlineServiceImpl implements KlineService {
private final KlineDao klineDao;
@Override
public void addKine(Kline kline) {
LocalDateTime localDateTime = LocalDateTime.now().withSecond(0).withNano(0);
long milli = localDateTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
Kline data = new Kline();
data.setId(System.currentTimeMillis());
data.setMarketCode("HK");
data.setSymbol("00070.HK");
data.setSymbolId(114554L);
data.setKlineType("M");
data.setTime(milli);
data.setTradeDate("2025-02-24");
data.setOpen(new BigDecimal(0));
data.setHigh(new BigDecimal(0));
data.setLow(new BigDecimal(0));
data.setClose(new BigDecimal(0));
data.setVolume(new BigDecimal(0));
data.setAmount(new BigDecimal(0));
data.setVwap(new BigDecimal(0));
data.setCount(0);
data.setSessionId(1);
klineDao.insert(data);
}
@Override
public List<Kline> getKine() {
return klineDao.selectBySymbolWithTime("HK", "00070.HK", "M");
}
}
package com.zzc.sharding.controller;
import com.zzc.sharding.entity.sharding.Kline;
import com.zzc.sharding.service.KlineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping(value = "/v1/kline/")
@RequiredArgsConstructor
public class KlineController {
private final KlineService klineService;
@RequestMapping(value = "add")
public Object addKine() {
klineService.addKine(new Kline());
return "success";
}
@RequestMapping(value = "get")
public Object getKine() {
return klineService.getKine();
}
}