"com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value" 按位 'OR'
"com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value" with bitwise 'OR'
我在使用 MySQL 按位 'OR' 时发现了一个奇怪的行为。帮助了解此行为的原因。
例如:
我们创建 table outOfRangeTest:
CREATE TABLE mttOutOfRangeTest (long_field BIGINT NOT NULL);
在table中插入一个负数-1。交易成功:
INSERT INTO mttOutOfRangeTest (long_field) VALUES (-1)
但是当您尝试使用按位 'OR' which return -1 时会出现奇怪的行为。
long value1 = new BigInteger("0000000000000000000000000000001111111111111111111111111111111111", 2).longValue(); // 17179869183L
long value2 = new BigInteger("1111111111111111111111111111110000000000000000000000000000000000", 2).longValue(); // -17179869184L
long resultInJava = value1 | value2; // result = -1;
如果您通过 JDBC 更新字段:
PreparedStatement pstmt = connection.prepareStatement("INSERT INTO mttOutOfRangeTest (long_field) VALUES (?)");
pstmt.setLong(1, value1);
pstmt.executeUpdate();
pstmt = connection.prepareStatement("UPDATE mttOutOfRangeTest SET long_field = (long_field | ?)");
pstmt.setLong(1, value2);
pstmt.executeUpdate();
有一个例外:
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value for column 'long_field' at row 1
com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4230)
com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4164)
com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615)
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2838)
com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2334)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2262)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2246)
sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:100)
org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
$java.sql.Statement$$EnhancerByProxool$b0edd73.executeUpdate(<generated>)
com.mtt.openfire.test.integration.db.OutOfRangeExceptionTest.testUpdateOutOfRange(OutOfRangeExceptionTest.java:78)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
如果您通过 MySql 命令行更新字段:
INSERT INTO mttOutOfRangeTest (long_field) VALUES (17179869183);
UPDATE mttOutOfRangeTest SET long_field = (long_field | -17179869184);
结果是 9223372036854775807(最大长值),但不是 -1。
OR 运算符 |
适用于无符号 64 位整数。 -1L
不在该范围内。显然,参数也必须是无符号的。所以不要使用 setLong,但可能 setObject(... BigInteger ...)
或:
BigDecimal n = new BigDecimal(Long.MAX_VALUE); // 0111...111
n = n.multiply(BigDecimal.TWO).add(BigDecimal.ONE); // 111...111
pstmt.setBigDecimal(1, n);
我在使用 MySQL 按位 'OR' 时发现了一个奇怪的行为。帮助了解此行为的原因。
例如: 我们创建 table outOfRangeTest:
CREATE TABLE mttOutOfRangeTest (long_field BIGINT NOT NULL);
在table中插入一个负数-1。交易成功:
INSERT INTO mttOutOfRangeTest (long_field) VALUES (-1)
但是当您尝试使用按位 'OR' which return -1 时会出现奇怪的行为。
long value1 = new BigInteger("0000000000000000000000000000001111111111111111111111111111111111", 2).longValue(); // 17179869183L
long value2 = new BigInteger("1111111111111111111111111111110000000000000000000000000000000000", 2).longValue(); // -17179869184L
long resultInJava = value1 | value2; // result = -1;
如果您通过 JDBC 更新字段:
PreparedStatement pstmt = connection.prepareStatement("INSERT INTO mttOutOfRangeTest (long_field) VALUES (?)");
pstmt.setLong(1, value1);
pstmt.executeUpdate();
pstmt = connection.prepareStatement("UPDATE mttOutOfRangeTest SET long_field = (long_field | ?)");
pstmt.setLong(1, value2);
pstmt.executeUpdate();
有一个例外:
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Out of range value for column 'long_field' at row 1
com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4230)
com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4164)
com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615)
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2838)
com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2082)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2334)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2262)
com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2246)
sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:100)
org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
$java.sql.Statement$$EnhancerByProxool$b0edd73.executeUpdate(<generated>)
com.mtt.openfire.test.integration.db.OutOfRangeExceptionTest.testUpdateOutOfRange(OutOfRangeExceptionTest.java:78)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
如果您通过 MySql 命令行更新字段:
INSERT INTO mttOutOfRangeTest (long_field) VALUES (17179869183);
UPDATE mttOutOfRangeTest SET long_field = (long_field | -17179869184);
结果是 9223372036854775807(最大长值),但不是 -1。
OR 运算符 |
适用于无符号 64 位整数。 -1L
不在该范围内。显然,参数也必须是无符号的。所以不要使用 setLong,但可能 setObject(... BigInteger ...)
或:
BigDecimal n = new BigDecimal(Long.MAX_VALUE); // 0111...111
n = n.multiply(BigDecimal.TWO).add(BigDecimal.ONE); // 111...111
pstmt.setBigDecimal(1, n);