本文從實際情況出發,解決生產中單表數據過大,和數據被拖庫導致的問題,並進行的解決方案。本案例使用的框架爲輕量型的
jfinal
,分表+數據庫脫敏,均採用了Apache的shardingsphere
。
首先我們要先明確這樣一個業務場景,如果生產上某個表的數據在100w+,那麼sql語句進行表操作,還不會出現什麼瓶頸問題,如果數據量再增加到500w+,可以通過索引,備份等方式,減少數據庫的單表壓力。如果繼續增加到1000w。或者單表一天的數據量就能達到1000w。那麼建議索引就無法在解決在這個問題。這時候,我們就需要通過分表的操作,來降低單表的壓力。
實現思路:
- 上面我們已經知道了問題所在,下面來分析一下解決方案。既然單個表無法滿足生產上是數據量,那麼就需要創建多個表。而如何將多個表進行關聯起來,我們就需要用到分表組件:ShardingSphere中的
sharding-jdbc
模塊。
解決方案:(全部代碼會在文末全部提供)
1.首先,我們數據庫中只有一張表 t_blog
。假設這張表的數據量已經達到的1000w的級別。接下來我們在創建8張表,表名爲t_blog_x
,這8張表的結構和原來的完全一樣,這8張表我們把它稱爲真實表
,而原來的t_blog
表,我們稱爲邏輯表
。
2.創建好表之後,接下來進行代碼部分實現。主要核心的class有下列三個。HashPreciseShardingAlgorithm
爲分表策略。ShardingCacheKit
爲緩存分表結果(可有可無)。ShardingDruidPlugin
分表數據源配置。
3.緊接着,我們需要在配置文件中,配置之分表內容。
# 主數據源
master.jdbcUrl = jdbc:mysql://localhost/jfinal_demo?characterEncoding=utf8&useSSL=false&zeroDateTimeBehavior=convertToNull
master.user = root
master.password =123456
## 分表規則 :對t_blog進分表,分表規則爲根據id進行分表,共分爲8張真實表
sharding = t_blog:8:id
devMode = true
4.在項目的主函數中配置分表代碼。
/**
* 配置插件
*/
public void configPlugin(Plugins me) {
// 配置 druid 數據庫連接池插件
Map<String,DruidPlugin> dataSourceMap = new HashMap<String, DruidPlugin>();
DruidPlugin masterPlugin = new DruidPlugin(p.get("master.jdbcUrl"), p.get("master.user"), p.get("master.password").trim());
dataSourceMap.put("jf_master",masterPlugin);
// 配置分表規則
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
shardingRuleConfiguration.setDefaultDataSourceName("jf_master");
shardingRuleConfiguration.setEncryptRuleConfig(getOrderEncryptRuleConfiguration());
List<TableRuleConfiguration> tableRuleConfigurations = new LinkedList<>();
// 讀取分表配置,生成分表規則
String sharding = p.get("sharding");
String [] rule = sharding.split(":");
if(!Objects.isNull(rule)){
// 1. 獲得真實表數目
int num = Integer.parseInt(rule[1]);
// 2.// 獲得邏輯表名
String tableName = rule[0];
// 3.// 分表字段
String shardingColumn = rule[2];
ShardingCacheKit.me().setCache(tableName,num);
// 4.分表規則和生成分表表達式
TableRuleConfiguration tableRuleConfiguration =
new TableRuleConfiguration(tableName,"jf_master." + tableName + "_${0.. " + (num -1 ) +"}");
// 5.配置分表策略
StandardShardingStrategyConfiguration shardingStrategyConfiguration =
new StandardShardingStrategyConfiguration(shardingColumn,new HashPreciseShardingAlgorithm());
tableRuleConfiguration.setTableShardingStrategyConfig(shardingStrategyConfiguration);
// 6. 加入策略
tableRuleConfigurations.add(tableRuleConfiguration);
shardingRuleConfiguration.setTableRuleConfigs(tableRuleConfigurations);
}
Properties props = new Properties();
props.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(),"true");
// 加入分表插件
ShardingDruidPlugin shardingDruidPlugin = new ShardingDruidPlugin(shardingRuleConfiguration,dataSourceMap,props);
me.add(shardingDruidPlugin);
// 配置ActiveRecord插件
ActiveRecordPlugin arp = new ActiveRecordPlugin(shardingDruidPlugin);
// 所有映射在 MappingKit 中自動化搞定
_MappingKit.mapping(arp);
me.add(arp);
// 配置緩存插件
me.add(new EhCachePlugin());
}
5.然後啓動項目進行測試,在這裏我寫了一個簡單的save方法,接口返回uuid和該數據存在的真實表
表名。
- 接口調用兩次後,我們可以看到,兩次的數據保存在了不同的表中。
7.接下來我們配置數據庫脫敏。
/**
* 脫敏配置
* @return
*/
private static EncryptRuleConfiguration getOrderEncryptRuleConfiguration() {
EncryptRuleConfiguration encryptRuleConfiguration = new EncryptRuleConfiguration();
Properties properties = new Properties();
// 設置算法的密鑰
properties.setProperty("aes.key.value", "123456");
// 將邏輯表t_blog的content列進行脫敏,算法採用AES
EncryptorRuleConfiguration encryptorRuleConfiguration =
new EncryptorRuleConfiguration("AES", "t_blog.content", properties);
encryptRuleConfiguration.getEncryptorRuleConfigs().put("user_encryptor", encryptorRuleConfiguration);
return encryptRuleConfiguration;
}
8.兩次數據庫中的內容如下
該項目源碼地址:
GitHub項目地址
參考文檔:
歡迎關注本人個人公衆號,交流更多技術信息