pan1998 opened a new issue, #37728:
URL: https://github.com/apache/shardingsphere/issues/37728

   When I use sharding-jdbc 5.5.2 to shard Oracle database tables, it fails to 
automatically shard and prompts that table A_Record does not exist.
   Operating environment: JDK11 + Hibernate 5.6 + Spring 5.2
   
   The content of applicationContext.xml is as follows:
   
   <?xml version="1.0" encoding="UTF-8" standalone="no"?>
   <beans xmlns="http://www.springframework.org/schema/beans";
        xmlns:aop="http://www.springframework.org/schema/aop"; 
        xmlns:context="http://www.springframework.org/schema/context";
        xmlns:jee="http://www.springframework.org/schema/jee"; 
        xmlns:tx="http://www.springframework.org/schema/tx";
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xsi:schemaLocation="http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd   
                            http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
                            http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.0.xsd   
                            http://www.springframework.org/schema/jee 
http://www.springframework.org/schema/jee/spring-jee-4.0.xsd   
                            http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd";>
        <context:property-placeholder 
location="classpath*:/application.properties" />
   
        <context:spring-configured /> 
   
        <context:component-scan base-package="org.nercita.dmp">
                <context:exclude-filter 
expression="org.springframework.stereotype.Controller" type="annotation" />
        </context:component-scan>
        
       <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" 
destroy-method="close">
           <property name="driverClassName" value="${db.driverClass}"/>
           <property name="jdbcUrl" value="${db.url}"/>
           <property name="username" value="${db.username}"/>
           <property name="password" value="${db.password}"/>
   
           <property name="connectionTimeout" value="30000"/> <!-- 连接超时时间(毫秒) 
-->
           <property name="idleTimeout" value="25200000"/>   <!-- 
空闲连接超时时间(毫秒),对应 C3P0 的 maxIdleTime -->
           <property name="maxLifetime" value="1800000"/>    <!-- 连接最大存活时间(毫秒) 
-->
           <property name="maximumPoolSize" value="10"/>     <!-- 最大连接数 -->
           <property name="minimumIdle" value="5"/>          <!-- 最小空闲连接数 -->
       </bean>
   
       <!-- ShardingSphere-JDBC -->
       <!-- 单表配置 -->
       <bean id="singleRuleConfiguration" 
class="org.apache.shardingsphere.single.config.SingleRuleConfiguration">
           <constructor-arg name="tables">
               <list>
                   <value>*.*</value>
               </list>
           </constructor-arg>
           <constructor-arg name="defaultDataSource" value="ds0"/>
       </bean>
       <!-- 分片表配置 -->
       <bean id="tRecordTableRuleConfiguration" 
class="org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration">
           <constructor-arg value="a_record"/>
           <constructor-arg value="ds0.a_record_$->{2025..2026}_q$->{1..4}"/>
           <property name="tableShardingStrategy">
               <bean 
class="org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration">
                  <constructor-arg value="recordTime"/>
                   <constructor-arg value="recordQuarterAlgorithm"/>
               </bean>
           </property>
           <property name="keyGenerateStrategy">
               <bean 
class="org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration">
                   <constructor-arg value="id"/>
                   <constructor-arg value="uuid"/>
               </bean>
           </property>
       </bean>
       <bean id="recordShardingRuleConfiguration" 
class="org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration">
           <property name="tables">
               <list>
                   <ref bean="tRecordTableRuleConfiguration"/>
               </list>
           </property>
   
           <property name="shardingAlgorithms">
               <map>
                   <entry key="recordQuarterAlgorithm">
                       <bean 
class="org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration">
                           <constructor-arg value="CLASS_BASED"/>
                           <constructor-arg>
                               <props>
                                   <prop key="strategy">STANDARD</prop>
                                   <prop 
key="strategyClassName">org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration</prop>
                                   <prop 
key="algorithmClassName">org.nercita.dmp.sharding.RecordQuarterShardingAlgorithm</prop>
                               </props>
                           </constructor-arg>
                       </bean>
                   </entry>
               </map>
           </property>
   
           <property name="keyGenerators">
               <map>
                   <entry key="uuid">
                       <bean 
class="org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration">
                           <constructor-arg value="UUID"/>
                           <constructor-arg>
                               <props></props>
                           </constructor-arg>
                       </bean>
                   </entry>
               </map>
           </property>
   
           <!-- 默认数据库策略(不分库) -->
           <property name="defaultDatabaseShardingStrategy">
               <bean 
class="org.apache.shardingsphere.sharding.api.config.strategy.sharding.NoneShardingStrategyConfiguration"/>
           </property>
           <!-- 默认表策略(不分表) -->
           <property name="defaultTableShardingStrategy">
               <bean 
class="org.apache.shardingsphere.sharding.api.config.strategy.sharding.NoneShardingStrategyConfiguration"/>
           </property>
       </bean>
   
       <bean id="shardingDataSource" 
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
           <property name="targetClass" 
value="org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory"/>
           <property name="targetMethod" value="createDataSource"/>
           <property name="arguments">
               <list>
                   <value>${hibernate.default_schema}</value>
                   <map>
                       <entry key="ds0" value-ref="dataSource"/>
                   </map>
                   <list>
                       <ref bean="singleRuleConfiguration"/>
                       <ref bean="recordShardingRuleConfiguration"/>
                   </list>
                   <props>
                   </props>
               </list>
           </property>
       </bean>
   
   
       <!-- sessionFactory -->
       <bean id="sessionFactory" 
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
           <property name="dataSource">
                        <ref bean="shardingDataSource" />
                </property>
                <property name="hibernateProperties">
                        <props>
                                <prop 
key="hibernate.dialect">${hibernate.dialect}</prop>
                                <prop 
key="hibernate.show_sql">${hibernate.show_sql}</prop>
                                <prop 
key="hibernate.format_sql">${hibernate.format_sql}</prop>
                                <prop 
key="hibernate.cache.use_second_level_cache">${hibernate.use_second_level_cache}</prop>
                                <prop 
key="hibernate.cache.use_query_cache">${hibernate.use_query_cache}</prop>
                                <prop 
key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                                <prop 
key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl}</prop>
                                <prop 
key="hibernate.default_schema">${hibernate.default_schema}</prop>
                                <prop key="hibernate.jdbc.fetch_size">100</prop>
                                <prop key="hibernate.jdbc.batch_size">50</prop>
   
                        </props>
                </property>
                <property name="packagesToScan">
                        <list>
                              <value>org.nercita.dmp.**.domain**</value>
                        </list>
                </property>
        </bean>
   
       <!-- 事务管理器 -->
        <bean id="transactionManager" 
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
                <property name="sessionFactory" ref="sessionFactory" />
        </bean> 
   
       <!-- 开启注解事务 -->
        <tx:annotation-driven transaction-manager="transactionManager" />
   
       <!-- 获取spring上下文 的ApplicationContextAware的实现Bean -->
        <bean  class="org.nercita.core.utils.SpringContextHolder" 
lazy-init="false" />
   
        <import resource="classpath*:/applicationContext-activemq.xml" />
   
        <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
                <constructor-arg name="poolConfig" 
ref="poolConfig"></constructor-arg>
                <constructor-arg name="host" 
value="${redis.host}"></constructor-arg>
                <constructor-arg name="port" 
value="${redis.port}"></constructor-arg>
                <constructor-arg name="password" 
value="${redis.password}"></constructor-arg>
                <constructor-arg name="timeout" value="2000"></constructor-arg>
                <constructor-arg name="database" 
value="${redis.database}"></constructor-arg>
        </bean>
        <bean id="poolConfig" 
class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
        </bean>
   
   </beans>
   
   hibernate.dialect=org.hibernate.dialect.DmDialect
   db.driverClass=dm.jdbc.driver.DmDriver
   db.url 
=jdbc:dm://192.168.1.12:5236/DMP?compatibleMode=oracle&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
   hibernate.default_schema=DMP
   
   
   
   @Entity
   @Table(name = "A_RECORD")
   public class Record extends BaseUidEntity {
   
       private static final long serialVersionUID = 1L;
   
       @Column(length = 255)
       private String tname;
   
       @Column
       private Date recordTime;
   
       private String mydatestr;
   
       public String getTname() {
           return tname;
       }
   
       public void setTname(String tname) {
           this.tname = tname;
       }
   
       public Date getRecordTime() {
           return recordTime;
       }
   
       public void setRecordTime(Date recordTime) {
           this.recordTime = recordTime;
       }
   
       public String getMydatestr() {
           return mydatestr;
       }
   
       public void setMydatestr(String mydatestr) {
           this.mydatestr = mydatestr;
       }
   }
   
   public final class RecordQuarterShardingAlgorithm implements 
StandardShardingAlgorithm<Date> {
       private Properties props = new Properties();
   
       @Override
       public void init(Properties properties) {
           this.props = properties;
       }
   
       @Override
       public String getType() {
           return "RECORD_QUARTER";
       }
   
       @Override
       public String doSharding(Collection<String> availableTargetNames, 
PreciseShardingValue<Date> shardingValue) {
           Date dt = shardingValue.getValue();
           String suffix = suffixOf(dt);
           String logicTable = shardingValue.getLogicTableName();
   
           // 根据逻辑表名和计算出的后缀查找实际表名
           for (String tableName : availableTargetNames) {
               if (tableName.toLowerCase().startsWith(logicTable.toLowerCase() 
+ "_") &&
                   tableName.toLowerCase().endsWith(suffix.toLowerCase())) {
                   return tableName;
               }
           }
   
           // 如果在availableTargetNames中未找到匹配的表,则构造表名
           return logicTable + "_" + suffix;
       }
   
       @Override
       public Collection<String> doSharding(Collection<String> 
availableTargetNames, RangeShardingValue<Date> shardingValue) {
           Date lower = shardingValue.getValueRange().hasLowerBound() ? 
shardingValue.getValueRange().lowerEndpoint() : null;
           Date upper = shardingValue.getValueRange().hasUpperBound() ? 
shardingValue.getValueRange().upperEndpoint() : null;
           List<String> result = new ArrayList<>();
           String logicTable = shardingValue.getLogicTableName();
   
           if (lower == null && upper == null) {
               return availableTargetNames;
           }
   
           Calendar cal = Calendar.getInstance();
           if (lower == null) {
               cal.setTime(upper);
               cal.add(Calendar.YEAR, -1);
               lower = cal.getTime();
           }
           if (upper == null) {
               cal.setTime(lower);
               cal.add(Calendar.YEAR, 1);
               upper = cal.getTime();
           }
   
           Set<String> targetSuffixes = new HashSet<>();
           Calendar tempCal = Calendar.getInstance();
           tempCal.setTime(lower);
   
           // 计算范围内的所有季度
           while (!tempCal.getTime().after(upper)) {
               targetSuffixes.add(suffixOf(tempCal.getTime()));
               tempCal.add(Calendar.MONTH, 1); // 每月检查一次,确保覆盖所有季度
           }
   
           // 从availableTargetNames中找出符合要求的表名
           for (String tableName : availableTargetNames) {
               for (String suffix : targetSuffixes) {
                   if 
(tableName.toLowerCase().startsWith(logicTable.toLowerCase() + "_") &&
                       tableName.toLowerCase().endsWith(suffix.toLowerCase())) {
                       result.add(tableName);
                       break;
                   }
               }
           }
   
           return result;
       }
   
       private String suffixOf(Date date) {
           Calendar cal = Calendar.getInstance();
           cal.setTime(date);
           int month = cal.get(Calendar.MONTH) + 1; // Calendar.MONTH从0开始,所以+1
           int quarter = (month - 1) / 3 + 1;      // 
计算季度,1-3月为第1季度,4-6月为第2季度,以此类推
           return new SimpleDateFormat("yyyy").format(cal.getTime()) + "_q" + 
quarter;
       }
   
       private List<String> quartersBetween(Date start, Date end) {
           Calendar cal = Calendar.getInstance();
           cal.setTime(start);
           List<String> res = new ArrayList<>();
   
           while (!cal.getTime().after(end)) {
               String suffix = suffixOf(cal.getTime());
               if (!res.contains(suffix)) {
                   res.add(suffix);
               }
               cal.add(Calendar.MONTH, 3); // 每次跳3个月,即一个季度
           }
   
           return res;
       }
   }
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: 
[email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to