这里主要刷针对的范围分区,其它类型分区表的场景没有遇见过,一般来说都是使用分区插件管理。我还是提供一个代码处理的思路。
1.首先分区表中至少有一个范围分区了,这里以时间作为分区。主要是提供一个分区增长的策略。
2.通过前面的sql查询数据库中的分区表信息。
3.逐个解析分区表。
思路:分区表都是时间分区,分区范围小时、天、月、季度建立,不会到分钟的粒度。定时检测,通过配置设置,预留的分区和需要一次创建的分区个数。当前时间到达预留分区时,立即创建分区。例如以天创建分区,预留3天,一次创建90天。则当前时间与数据库最后一个分区时间对比,已经到达最后三天,则立即创建已有分区的后90天分区。如果今天是8号,则分区表中最后一个是11号,则立即创建11号后90天的分区。
给大家贴一个关键代码,代码考虑,以下代码:
java
package org.db.partition.task;
import org.db.partition.configuration.PartDBConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class PartitionedTableTask implements CommandLineRunner {
@Autowired
PartDBConfig partDBConfig;
//查询分区
String sql="select * FROM ( SELECT parent.relname parent,\n" +
" child.relname child,\n" +
" CASE WHEN child.relispartition THEN pg_get_expr(child.relpartbound, child.oid) ELSE NULL END AS\n" +
" partition_bound\n" +
"FROM pg_inherits\n" +
"JOIN pg_class parent ON pg_inherits.inhparent = parent.oid\n" +
"JOIN pg_class child ON pg_inherits.inhrelid = child.oid) as part\n" +
"\n" +
"WHERE partition_bound is not null ORDER BY partition_bound\n";
//创建分区,参数顺序 分区表名、父表、分区范围
String format="CREATE TABLE %s PARTITION OF %s\n" +
" \n" +
"FOR VALUES FROM ('%s') TO ('%s');";
@Override
public void run(String... args) throws Exception {
while (true) {
Connection connection = DBUtil.getConnection(partDBConfig);
try {
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);
List<ChildTable> list = new ArrayList<ChildTable>();
while (rs.next()) {
ChildTable childTable = new ChildTable();
childTable.setParent(rs.getString("parent"));
childTable.setChild(rs.getString("child"));
childTable.setBound(rs.getString("partition_bound"));
list.add(childTable);
}
//按照父表分组
Map<String, List<ChildTable>> groupedBy = list.stream()
.collect(Collectors.groupingBy(ChildTable::getParent));
groupedBy.forEach((parent, child) -> {
try {
//取出最后一个分区
ChildTable table = child.get(child.size() - 1);
/**
* 获取分区范围,正则表达式提取时间
* FOR VALUES FROM ('2025-01-01') TO ('2025-04-01')
*/
table.process();
if (table.getEnd() != null) {
LocalDateTime now = LocalDateTime.now();
//分区开始
LocalDateTime startTime = AutoDateParser.parse(table.getStart());
//分区结束
LocalDateTime endTime = AutoDateParser.parse(table.getEnd());
//计算一个分区时长
long minutesBetween = ChronoUnit.MINUTES.between(startTime, endTime);
//计算当前时间到最后一个分区的时间
long secondsBetween = ChronoUnit.SECONDS.between(now, endTime);
//如果当前时间到最后一个分区的时间小于预留的时间
if (secondsBetween < partDBConfig.getNum() * minutesBetween) {
//开始创建
LocalDateTime nextTime = endTime;
//需要一次创建的分区个数
for (int i = 0; i < partDBConfig.getPre(); i++) {
LocalDateTime addTime = nextTime.plus(Duration.ofMinutes(minutesBetween));
String name = addTime.format(DateTimeFormatter.ofPattern("yyyy_MM_dd_HH"));
String add = String.format(format, "part_" + name, table.getParent(), nextTime, addTime);
try {
connection.createStatement().execute(add);
} catch (SQLException e) {
throw new RuntimeException(e);
}
//
nextTime = addTime;
}
}
}
}catch (Exception e){
e.printStackTrace();
}
});
DBUtil.closeJDBC(rs, statement, connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
Thread.sleep(1000*60*50);
}
}
}