数据库的瓶颈是所有web系统的难题,之前的文章已经介绍了,分库分表来解决单一的表存储压力问题,在实际项目使用过程,也抗住了压力,完美的应付了项目需求。分区对于实际开发使用,集成和维护更加便捷,同样可以解决单一表的数据存储压力。
国产数据库高度雷同,都有mysql、oracle、postgresql等数据库的影子。openGauss最大的优点是开源免费且是国产,随着项目交付的国产化压力,openGauss成为国产化的成功替代方案。
当前的框架和sql自升级方案,支持n种数据库集成,目前项目已集成3种数据库,基本上适配所有的项目需求,更多的数据库集成,自行研究和解决
分表分库参考之前的文章:
spring boot 分库分表 shardingsphere_shardingsphere springboot 分库分表-优快云博客
当然对于iot类的数据,这类数据大而急,数据存储压力大,汇总需求多,常规的数据库不能适用,至于后续用什么数据库替代,后续会补充。
1、不同数据库集成
3种数据库都支持mybatis-plus集成,对于通用的增删改查,可以用公共方法,对于语法不同的处理,建立3个文件夹,区分加载不同数据库,配置文件实现具体的sql。
配置上,yaml指向不同的sql文件和不同的数据库连接
2、sql自升级
通用的sql自升级文件是flyway,普通的互联网程序完全满足。对于复杂的系统,集成不同的数据库的系统,无法满足。自己集成sql升级系统,完全可以做到自定义处理。
R:R开头的文件,可以重复执行
V:V开头文件,只执行一次,不可重复执行
table_history:执行记录表,已执行过的sql文件不重复执行
系统每次启动都重新执行该方法,完成sql的初始升级
package com.tetrabot.operation.conf;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.tetrabot.base.handler.PartitionTableHandler;
import com.tetrabot.operation.mapper.TableCreateMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.ResourceUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.*;
/**
* 数据sql执行工具
*/
@Slf4j
@Configuration
@Order(1)
public class CustomizeDataSourceInitializer {
@javax.annotation.Resource
private TableCreateMapper tableCreateMapper;
@Autowired
private PartitionTableHandler partitionTableHandler;
@Bean
public DataSourceInitializer dataSourceInitializer(final DataSource dataSource) throws SQLException {
final DataSourceInitializer initializer = new DataSourceInitializer();
// 设置数据源
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(databasePopulator(dataSource));
return initializer;
}
private DatabasePopulator databasePopulator(DataSource dataSource) throws SQLException {
String baseUrl = null;
Connection connection = dataSource.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
String databaseProductName = metaData.getDatabaseProductName();
if (tableCreateMapper.existTable() <= 0) {
log.info("sql upgrade table not exist");
tableCreateMapper.createTable();
}
// 已经执行过的文件
List<String> finishFile = tableCreateMapper.finishSql();
if ("MySQL".equalsIgnoreCase(databaseProductName)) {
baseUrl = ResourceUtils.CLASSPATH_URL_PREFIX + "db/mysql/";
} else if ("DM DBMS".equalsIgnoreCase(databaseProductName)) {
baseUrl = ResourceUtils.CLASSPATH_URL_PREFIX + "db/dm/";
}else if ("PostgreSQL".equalsIgnoreCase(databaseProductName)) {
baseUrl = ResourceUtils.CLASSPATH_URL_PREFIX + "db/gauss/";
} else {
log.error("Unknown database: " + databaseProductName);
}
final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
Resource[] resources = new Resource[0];
try {
resources = new PathMatchingResourcePatternResolver().
getResources(baseUrl + "*.sql");
} catch (IOException e) {
e.printStackTrace();
log.error("get sql upgrade file failed:{}", e.getMessage());
}
// 可重复变迁的sql脚本
List<Resource> repeatable = new ArrayList<>();
// 文件读取顺序未按照数字大小排序,需要手动排序执行sql文件
TreeMap<Integer, Resource> sortMap = new TreeMap<>(Integer::compareTo);
for (Resource resource : resources) {
String fileName = resource.getFilename();
if (fileName.contains("R")) {
repeatable.add(resource);
continue;
}
if (finishFile.contains(fileName)) {
continue;
}
// 无法获取是否升级成功
Map<String, O