ResultSet.updateRow() 产生 "Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'"
ResultSet.updateRow() produces "Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'"
我有以下 table,其中 name
是 LATIN1,其余是 UTF8。
CREATE TABLE `test_names` (
`name` varchar(500) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`other_stuff_1` int DEFAULT NULL,
`other_stuff_2` varchar(45) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
我在Java中遇到以下问题:
我SELECT ... FOR UPDATE
。然后我在其 ResultSet 上调用 updateInt(2, 1)
和 updateRow()
并得到 Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'
.
如何在不更改 table 的/连接的字符集的情况下完成这项工作?
非常感谢。
---更新---
我使用SELECT name, other_stuff_1 FROM test_names LIMIT 1 FOR UPDATE;
,连接字符串是DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + db + "?allowMultiQueries=true", user, password);
。
确切的堆栈跟踪是:
java.sql.SQLException: Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1086)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4237)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4169)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2834)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2441)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2366)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2350)
at com.mysql.jdbc.UpdatableResultSet.updateRow(UpdatableResultSet.java:2405)
问题是您正在尝试从 table 中 select ,它在不同的列上具有不同的字符集。
您必须使用 CONVERT()
将查询中具有不同字符集的列转换为正确的字符集。
http://dev.mysql.com/doc/refman/5.7/en/charset-convert.html
对于您的情况,您应该将查询修改为:
SELECT CONVERT(name USING latin1), other_stuff_1 FROM test_names LIMIT 1 FOR UPDATE;
恕我直言,在这种情况下,当 table 中的编码不统一时,您不能使用 updatable 结果集(例如,主键在 latin1 中,但其他列在 utf8 中).
正如 Andras 所指出的,您可以在 sql 端转换编码,但是您将无法更新结果集。
为什么不直接用 executeUpdate(...) 更新 table?您可以使用简单的 select 缩小目标行的范围,然后遍历生成的主键列表并调用 executeUpdate。
对我来说,它适用于混合编码列。举个例子:
conn.setAutoCommit(false);
ResultSet rs = st.executeQuery("SELECT name other_stuff_1 FROM test_names");
List<String> keys = new ArrayList<String>();
while(rs.next()) {
keys.add(rs.getString(1));
}
rs.close();
for(String key : keys) {
st.executeUpdate("update test_names set other_stuff_1='"+key.length()+"', other_stuff_2='" + key.toUpperCase() + "' where name='" + key + "'");
}
conn.commit();
我这边可以给你一些建议
- 首先更新您的 Connector/J 最新版本。
- 运行 这个查询
SET NAMES='utf8'
将 &characterEncoding=UTF-8
添加到您的 JDBC 连接字符串。希望你已经做到了。
使用convert() for insert or update
和cast() for select
查询。更多详情 http://dev.mysql.com/doc/refman/5.7/en/charset-convert.html
- 对于“排序规则的非法混合”相关问题,您可以跟进Troubleshooting "Illegal mix of collations" error in mysql
我有以下 table,其中 name
是 LATIN1,其余是 UTF8。
CREATE TABLE `test_names` (
`name` varchar(500) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`other_stuff_1` int DEFAULT NULL,
`other_stuff_2` varchar(45) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
我在Java中遇到以下问题:
我SELECT ... FOR UPDATE
。然后我在其 ResultSet 上调用 updateInt(2, 1)
和 updateRow()
并得到 Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'
.
如何在不更改 table 的/连接的字符集的情况下完成这项工作?
非常感谢。
---更新---
我使用SELECT name, other_stuff_1 FROM test_names LIMIT 1 FOR UPDATE;
,连接字符串是DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + db + "?allowMultiQueries=true", user, password);
。
确切的堆栈跟踪是:
java.sql.SQLException: Illegal mix of collations (latin1_bin,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '<=>'
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1086)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4237)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4169)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2834)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2441)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2366)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2350)
at com.mysql.jdbc.UpdatableResultSet.updateRow(UpdatableResultSet.java:2405)
问题是您正在尝试从 table 中 select ,它在不同的列上具有不同的字符集。
您必须使用 CONVERT()
将查询中具有不同字符集的列转换为正确的字符集。
http://dev.mysql.com/doc/refman/5.7/en/charset-convert.html
对于您的情况,您应该将查询修改为:
SELECT CONVERT(name USING latin1), other_stuff_1 FROM test_names LIMIT 1 FOR UPDATE;
恕我直言,在这种情况下,当 table 中的编码不统一时,您不能使用 updatable 结果集(例如,主键在 latin1 中,但其他列在 utf8 中).
正如 Andras 所指出的,您可以在 sql 端转换编码,但是您将无法更新结果集。
为什么不直接用 executeUpdate(...) 更新 table?您可以使用简单的 select 缩小目标行的范围,然后遍历生成的主键列表并调用 executeUpdate。
对我来说,它适用于混合编码列。举个例子:
conn.setAutoCommit(false);
ResultSet rs = st.executeQuery("SELECT name other_stuff_1 FROM test_names");
List<String> keys = new ArrayList<String>();
while(rs.next()) {
keys.add(rs.getString(1));
}
rs.close();
for(String key : keys) {
st.executeUpdate("update test_names set other_stuff_1='"+key.length()+"', other_stuff_2='" + key.toUpperCase() + "' where name='" + key + "'");
}
conn.commit();
我这边可以给你一些建议
- 首先更新您的 Connector/J 最新版本。
- 运行 这个查询
SET NAMES='utf8'
将
&characterEncoding=UTF-8
添加到您的 JDBC 连接字符串。希望你已经做到了。使用
convert() for insert or update
和cast() for select
查询。更多详情 http://dev.mysql.com/doc/refman/5.7/en/charset-convert.html- 对于“排序规则的非法混合”相关问题,您可以跟进Troubleshooting "Illegal mix of collations" error in mysql