Pre Merge pull request !136 from 瞿佐鹏/master-jdk17-sharding-pr

pull/136/MERGE
瞿佐鹏 2024-09-29 00:08:35 +00:00 committed by Gitee
commit da319c03dc
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 416 additions and 166 deletions

165
pom.xml
View File

@ -1,165 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<modules>
<module>yudao-dependencies</module>
<module>yudao-gateway</module>
<module>yudao-framework</module>
<!-- 各种 module 拓展 -->
<module>yudao-module-system</module>
<module>yudao-module-infra</module>
<module>yudao-module-member</module>
<module>yudao-module-bpm</module>
<module>yudao-module-pay</module>
<module>yudao-module-report</module>
<module>yudao-module-mp</module>
<module>yudao-module-mall</module>
<module>yudao-module-crm</module>
<module>yudao-module-erp</module>
<module>yudao-module-ai</module>
</modules>
<name>${project.artifactId}</name>
<description>芋道项目基础脚手架</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>2.2.0-snapshot</revision>
<!-- Maven 相关 -->
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<!-- 看看咋放到 bom 里 -->
<lombok.version>1.18.34</lombok.version>
<spring.boot.version>3.3.1</spring.boot.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-dependencies</artifactId>
<version>${revision}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<!-- maven-surefire-plugin 插件,用于运行单元测试。 -->
<!-- 注意,需要使用 3.0.X+,因为要支持 Junit 5 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
<!-- https://stackoverflow.com/questions/33483697/re-run-spring-boot-configuration-annotation-processor-to-update-generated-metada -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<!-- 编译参数写在 arg 内,解决 Spring Boot 3.2 的 Parameter Name Discovery 问题 -->
<debug>false</debug>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- 统一 revision 版本 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version>
<configuration>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
<updatePomFile>true</updatePomFile>
</configuration>
<executions>
<execution>
<goals>
<goal>flatten</goal>
</goals>
<id>flatten</id>
<phase>process-resources</phase>
</execution>
<execution>
<goals>
<goal>clean</goal>
</goals>
<id>flatten.clean</id>
<phase>clean</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- 使用 huawei / aliyun 的 Maven 源,提升下载速度 -->
<repositories>
<repository>
<id>huaweicloud</id>
<name>huawei</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<repository>
<id>aliyunmaven</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>

View File

@ -152,6 +152,13 @@
<artifactId>hutool-extra</artifactId> <!-- 邮件 -->
</dependency>
<!-- 分表 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
<build>

View File

@ -6,9 +6,11 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogPageReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@DS("sharding")
public interface OperateLogMapper extends BaseMapperX<OperateLogDO> {
default PageResult<OperateLogDO> selectPage(OperateLogPageReqVO pageReqDTO) {

View File

@ -0,0 +1,90 @@
package cn.iocoder.yudao.module.system.framework.sharding;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import com.google.common.collect.Range;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
/**
* @Description
* ,,selectPagempcount,
*
* @Date 2024/6/13 10:07
* @Author tom
**/
@Getter
@Slf4j
public class DataPreciseShardingAlgorithm implements StandardShardingAlgorithm<LocalDateTime> {
@Override
public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<LocalDateTime> rangeShardingValue) {
Range<LocalDateTime> valueRange = rangeShardingValue.getValueRange();
LocalDateTime lowerEndpoint = valueRange.lowerEndpoint();
LocalDateTime upperEndpoint = valueRange.upperEndpoint();
// 逻辑表名
String logicTableName = rangeShardingValue.getLogicTableName();
List<String> tables = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
if (upperEndpoint.getYear() > now.getYear() || upperEndpoint.getMonthValue() > now.getMonthValue()) {
log.warn("时间区间异常 不能查询未来数据 {} {}",lowerEndpoint,upperEndpoint);
throw new ServiceException(40001,"不能查询未来数据");
}
while (lowerEndpoint.compareTo(upperEndpoint) <= 0) {
// 添加到集合
tables.add(buildTable(logicTableName, lowerEndpoint));
// 往后加一个月
lowerEndpoint = lowerEndpoint.plusMonths(1).withDayOfMonth(1);
}
return tables;
}
private String buildTable(String logicTableName, LocalDateTime startTime) {
String timeStr = DateUtil.formatLocalDateTime(startTime);
String year = timeStr.substring(2, 4);
String month = timeStr.substring(5, 7);
return logicTableName + "_" + year + month;
}
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<LocalDateTime> preciseShardingValue) {
String timeStr = DateUtil.formatLocalDateTime(preciseShardingValue.getValue());
String year = timeStr.substring(2, 4);
String month = timeStr.substring(5, 7);
String tableSuffix = year + month;
for (String s : collection) {
if (s.contains(tableSuffix)){
return s;
}
}
return null;
}
@Override
public Properties getProps() {
return null;
}
@Override
public void init(Properties properties) {
}
@Override
public String getType() {
return "HIS_DATA_SPI_BASED";
}
}

View File

@ -0,0 +1,73 @@
package cn.iocoder.yudao.module.system.framework.sharding;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import jakarta.annotation.Resource;
import org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class MyDataSourceConfiguration {
@Resource
private DynamicDataSourceProperties properties;
/**
* : shardingDataSource
* : masterSlaveDataSource
*
*/
// @Lazy
// @Resource
// private MasterSlaveDataSource masterSlaveDataSource;
// @Lazy
@Resource
private ShardingSphereDataSource shardingSphereDataSource;
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider(DefaultDataSourceCreator dataSourceCreator) {
return new AbstractDataSourceProvider(dataSourceCreator) {
@Override
public Map<String, DataSource> loadDataSources() {
Map<String, DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put("sharding", shardingSphereDataSource);
//下面的代码可以把 shardingJdbc 内部管理的子数据源也同时添加到动态数据源里 (根据自己需要选择开启+注解了@Lazy被代理了不可以)
// Map<String, DataSource> shardingInnerDataSources = shardingSphereDataSource();
// dataSourceMap.putAll(shardingInnerDataSources);
return dataSourceMap;
}
};
}
/**
*
* spring,
* shardingjdbc
* 3.4.0使, -
*/
@Primary
@Bean
public DataSource dataSource(List<DynamicDataSourceProvider> providers) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setSeata(properties.getSeata());
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}

View File

@ -0,0 +1,206 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.yaml.snakeyaml.representer;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.introspector.Property;
import org.yaml.snakeyaml.introspector.PropertyUtils;
import org.yaml.snakeyaml.nodes.*;
import java.util.*;
public class Representer extends SafeRepresenter {
protected Map<Class<? extends Object>, TypeDescription> typeDefinitions = Collections.emptyMap();
public Representer() {
super(new DumperOptions());
this.representers.put(null, new RepresentJavaBean());
}
public Representer(DumperOptions options) {
super(options);
this.representers.put(null, new RepresentJavaBean());
}
public TypeDescription addTypeDescription(TypeDescription td) {
if (Collections.EMPTY_MAP == this.typeDefinitions) {
this.typeDefinitions = new HashMap();
}
if (td.getTag() != null) {
this.addClassTag(td.getType(), td.getTag());
}
td.setPropertyUtils(this.getPropertyUtils());
return (TypeDescription)this.typeDefinitions.put(td.getType(), td);
}
public void setPropertyUtils(PropertyUtils propertyUtils) {
super.setPropertyUtils(propertyUtils);
Collection<TypeDescription> tds = this.typeDefinitions.values();
Iterator var3 = tds.iterator();
while(var3.hasNext()) {
TypeDescription typeDescription = (TypeDescription)var3.next();
typeDescription.setPropertyUtils(propertyUtils);
}
}
protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
List<NodeTuple> value = new ArrayList(properties.size());
Tag customTag = (Tag)this.classTags.get(javaBean.getClass());
Tag tag = customTag != null ? customTag : new Tag(javaBean.getClass());
MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO);
this.representedObjects.put(javaBean, node);
FlowStyle bestStyle = FlowStyle.FLOW;
Iterator var8 = properties.iterator();
while(true) {
NodeTuple tuple;
do {
if (!var8.hasNext()) {
if (this.defaultFlowStyle != FlowStyle.AUTO) {
node.setFlowStyle(this.defaultFlowStyle);
} else {
node.setFlowStyle(bestStyle);
}
return node;
}
Property property = (Property)var8.next();
Object memberValue = property.get(javaBean);
Tag customPropertyTag = memberValue == null ? null : (Tag)this.classTags.get(memberValue.getClass());
tuple = this.representJavaBeanProperty(javaBean, property, memberValue, customPropertyTag);
} while(tuple == null);
if (!((ScalarNode)tuple.getKeyNode()).isPlain()) {
bestStyle = FlowStyle.BLOCK;
}
Node nodeValue = tuple.getValueNode();
if (!(nodeValue instanceof ScalarNode) || !((ScalarNode)nodeValue).isPlain()) {
bestStyle = FlowStyle.BLOCK;
}
value.add(tuple);
}
}
protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
ScalarNode nodeKey = (ScalarNode)this.representData(property.getName());
boolean hasAlias = this.representedObjects.containsKey(propertyValue);
Node nodeValue = this.representData(propertyValue);
if (propertyValue != null && !hasAlias) {
NodeId nodeId = nodeValue.getNodeId();
if (customTag == null) {
if (nodeId == NodeId.scalar) {
if (property.getType() != Enum.class && propertyValue instanceof Enum) {
nodeValue.setTag(Tag.STR);
}
} else {
if (nodeId == NodeId.mapping && property.getType() == propertyValue.getClass() && !(propertyValue instanceof Map) && !nodeValue.getTag().equals(Tag.SET)) {
nodeValue.setTag(Tag.MAP);
}
this.checkGlobalTag(property, nodeValue, propertyValue);
}
}
}
return new NodeTuple(nodeKey, nodeValue);
}
protected void checkGlobalTag(Property property, Node node, Object object) {
if (!object.getClass().isArray() || !object.getClass().getComponentType().isPrimitive()) {
Class<?>[] arguments = property.getActualTypeArguments();
if (arguments != null) {
Class t;
Iterator iter;
Iterator var9;
if (node.getNodeId() == NodeId.sequence) {
t = arguments[0];
SequenceNode snode = (SequenceNode)node;
Iterable<Object> memberList = Collections.emptyList();
if (object.getClass().isArray()) {
memberList = Arrays.asList((Object[])object);
} else if (object instanceof Iterable) {
memberList = (Iterable)object;
}
iter = ((Iterable)memberList).iterator();
if (iter.hasNext()) {
var9 = snode.getValue().iterator();
while(var9.hasNext()) {
Node childNode = (Node)var9.next();
Object member = iter.next();
if (member != null && t.equals(member.getClass()) && childNode.getNodeId() == NodeId.mapping) {
childNode.setTag(Tag.MAP);
}
}
}
} else if (object instanceof Set) {
t = arguments[0];
MappingNode mnode = (MappingNode)node;
iter = mnode.getValue().iterator();
Set<?> set = (Set)object;
var9 = set.iterator();
while(var9.hasNext()) {
Object member = var9.next();
NodeTuple tuple = (NodeTuple)iter.next();
Node keyNode = tuple.getKeyNode();
if (t.equals(member.getClass()) && keyNode.getNodeId() == NodeId.mapping) {
keyNode.setTag(Tag.MAP);
}
}
} else if (object instanceof Map) {
t = arguments[0];
Class<?> valueType = arguments[1];
MappingNode mnode = (MappingNode)node;
iter = mnode.getValue().iterator();
while(iter.hasNext()) {
NodeTuple tuple = (NodeTuple)iter.next();
this.resetTag(t, tuple.getKeyNode());
this.resetTag(valueType, tuple.getValueNode());
}
}
}
}
}
private void resetTag(Class<? extends Object> type, Node node) {
Tag tag = node.getTag();
if (tag.matches(type)) {
if (Enum.class.isAssignableFrom(type)) {
node.setTag(Tag.STR);
} else {
node.setTag(Tag.MAP);
}
}
}
protected Set<Property> getProperties(Class<? extends Object> type) {
return this.typeDefinitions.containsKey(type) ? ((TypeDescription)this.typeDefinitions.get(type)).getProperties() : this.getPropertyUtils().getProperties(type);
}
protected class RepresentJavaBean implements Represent {
protected RepresentJavaBean() {
}
public Node representData(Object data) {
return Representer.this.representJavaBean(Representer.this.getProperties(data.getClass()), data);
}
}
}

View File

@ -0,0 +1 @@
cn.iocoder.yudao.module.system.framework.sharding.DataPreciseShardingAlgorithm

View File

@ -73,7 +73,43 @@ spring:
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: 123456
## sharding 配置
shardingsphere:
props:
sql:
show: true
sql-show: true
datasource:
names: db-0
db-0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8&rewriteBatchedStatements=true
rules:
sharding:
tables:
system_operate_log:
key-generator:
column: id
type: SNOWFLAKE
#分片策略
actual-data-nodes: db-0.system_operate_log_${24..50}0${1..9},db-0.system_operate_log_${24..50}1${0..2}
table-strategy: #表分片策略
standard:
sharding-column: create_time
sharding-algorithm-name: his_month_sharding
# 配置分片算法
sharding-algorithms:
# person_sync_record_inline:
# type: INLINE
# props:
# algorithm-expression: person_sync_record_$->{id % 16}
# 分片算法名称
his_month_sharding:
# 分片算法类型这个type是我们的分片算法实现类中 getType()的返回值SPI适用于这种方式
type: HIS_DATA_SPI_BASED
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis: