-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Open
Labels
Description
Related code:
HashModShardingAlgorithm.java
private long hashShardingValue(final Object shardingValue) {
return Math.abs((long) shardingValue.hashCode());
}
Possible issue 1
java.lang.Number sub-classes might have different hashCode() implementation, e.g.
println("Integer.valueOf(-1).hashCode(): " + Integer.valueOf(-1).hashCode())
println("Long.valueOf(-1).hashCode(): " + Long.valueOf(-1).hashCode())
println("BigInteger.valueOf(-1).hashCode(): " + BigInteger.valueOf(-1).hashCode())
-- result
Integer.valueOf(-1).hashCode(): -1
Long.valueOf(-1).hashCode(): 0
BigInteger.valueOf(-1).hashCode(): -1
Eexample table: t_order.
Sharding rule:
rules:
- !SHARDING
autoTables:
t_order:
actualDataSources: ds_0,ds_1
shardingStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: auto_mod
keyGenerateStrategy:
column: user_id
keyGeneratorName: snowflake
shardingAlgorithms:
auto_mod:
type: HASH_MOD
props:
sharding-count: 2
keyGenerators:
snowflake:
type: SNOWFLAKE
Insert record with Integer sharding key value, then query with Long sharding key value, ResultSet return empty result.
Test code:
@Test
void assertHashModSetLongOnIntColumnWorks() throws SQLException {
try (Connection connection = DriverManager.getConnection("jdbc:shardingsphere:classpath:config/driver/foo-driver-fixture.yaml")) {
assertThat(connection, isA(ShardingSphereConnection.class));
try (Statement statement = connection.createStatement()) {
statement.execute("DROP TABLE IF EXISTS t_order");
statement.execute("CREATE TABLE t_order (order_id INT PRIMARY KEY, user_id INT)");
}
int value = -1;
try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO t_order (order_id, user_id) VALUES (?, ?)")) {
preparedStatement.setObject(1, value); // Insert with Integer value
preparedStatement.setObject(2, 101);
int updatedCount = preparedStatement.executeUpdate();
assertThat(updatedCount, is(1));
}
try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM t_order WHERE order_id = ?")) {
preparedStatement.setObject(1, value); // Query with Integer value, related record could be queried out
ResultSet resultSet = preparedStatement.executeQuery();
assertTrue(resultSet.next()); // Pass
assertThat(resultSet.getInt(1), is(value)); // Pass
resultSet.close();
}
try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM t_order WHERE order_id = ?")) {
preparedStatement.setObject(1, (long) value); // Query with Long value, related record could NOT be queried out
ResultSet resultSet = preparedStatement.executeQuery();
assertTrue(resultSet.next()); // WRONG
assertThat(resultSet.getInt(1), is(value));
resultSet.close();
}
}
}
It was submitted in https://github.com/apache/shardingsphere/pull/37281/files
The similar test code, use raw MySQL JDBC driver, test on MySQL, it works.
Possible issue 2
If different vendors JRE or different versions of JRE have different hashCode() implementation, then when JRE vendor or version is changed, it'll cause different routing for the same sharding value.