数据库分片使用ShardingSphere-Proxy作为数据库代理端,java应用连接有时候表现并不是跟直连后端数据库一样,切换到连接数据库代理就会遇到各种各样的问题,比如最近就遇到在做包含时间分片的数据查询时抛出错误Sharding value must implements Comparable. 的问题。网上很多遇到该问题都是在数据插入时遇到,而我们这次不同,是在做数据查询时遇到该问题。以下将描述问题情况及解决办法。
1. 问题描述
1.1 当前使用环境
ShardingSphere-Proxy版本:shardingsphere-proxy-5.3.1
后端数据库:PostgreSQL-12.1
java端:Mybatis-Plus
1.2 ShardingSphere-Proxy的分片算法配置
1
2
3
4
5
6
7
8
9
10
|
datetime_year_month_interval_algorithm:
type: INTERVAL
props:
datetime-pattern: 'yyyy-MM-dd HH:mm:ss'
datetime-lower: '2023-01-01 00:00:00'
#默认当前时间
datetime-upper: '2023-12-31 23:59:59'
sharding-suffix-pattern: 'yyyyMM'
datetime-interval-amount: 1
datetime-interval-unit: 'MONTHS'
|
1.3 java调用
1
2
|
Date date1 = new Date();
orderMapper.getData(xxx,date1);
|
1.4 Mapper配置
1
2
3
4
5
6
7
8
|
<select id="getData" resultType="integer">
select
count(*)
from
ttt
where
and create_time <![CDATA[ <= ]]> #{qTime}
</select>
|
1.5 出现报错
1
2
3
4
5
6
7
8
9
|
### Cause: org.postgresql.util.PSQLException: ERROR: Sharding value must implements Comparable.
; ERROR: Sharding value must implements Comparable.; nested exception is org.postgresql.util.PSQLException: ERROR: Sharding value must implements Comparable.
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:107)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
at com.sun.proxy.$Proxy134.selectOne(Unknown Source)
|
从上述重点可看出报错信息是:Sharding value must implements Comparable
说明与类型有关。
2. 调试分析
先把调用的类型修改为LocalDateTime
1
2
|
LocalDateTime date1 = LocalDateTime.now();
orderMapper.getData(xxx,date1);
|
结果发现可以调用。
3. 解决办法
从上述调试分析,可以看出,我们可以通过转变Date类型为LocalDateTime来解决这个问题,但考虑尽量少改动原来的代码,我们写一个TypeHandler来全局转变Date类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.stereotype.Component;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
/**
* 功能描述:
*
* @author https://tech.hiofd.com
* @date 2023-03-13 17:10
*/
@Component
@MappedTypes(Date.class)
@MappedJdbcTypes(value = JdbcType.DATE, includeNullJdbcType = true)
public class MyDateTypeHandler extends BaseTypeHandler<Date> {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date parameter, JdbcType jdbcType) throws SQLException {
LocalDateTime localDateTime = LocalDateTime.ofInstant(parameter.toInstant(), ZoneId.systemDefault());
System.out.println(localDateTime);
preparedStatement.setObject(i, localDateTime);
}
@Override
public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
Object v = rs.getObject(columnName);
if (v == null) {
return null;
}
Date date1 = null;
try {
date1 = formatter.parse(v.toString());
System.out.println(date1);
return date1;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Object v = rs.getObject(columnIndex);
if (v == null) {
return null;
}
Date date1 = null;
try {
date1 = formatter.parse(v.toString());
System.out.println(date1);
return date1;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
@Override
public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Object v = cs.getObject(columnIndex);
if (v == null) {
return null;
}
Date date1 = null;
try {
date1 = formatter.parse(v.toString());
System.out.println(date1);
return date1;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
|
至此,问题完美解决。