MySQL開啟RewriteBatchedStatements後PreparedStatement的一個異常

來源:互聯網
上載者:User

標籤:string index out of range: -36

【問題描述】:

MySQL 開啟 RewriteBatchedStatements 屬性後,PreparedStatement在解析一種Insert形式的SQL時發生異常,測試代碼如下,使用的MySQL驅動為mysql-connector-java-5.1.36-bin.jar:

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;public class Demo{    public static final String DBDRIVER = "com.mysql.jdbc.Driver";    public static final String DBURL = "jdbc:mysql://127.0.0.1:3306/S10?rewriteBatchedStatements=true";    public static final String DBUSER = "root";    public static final String DBPASS = "123456";    public static void main(String[] args)    {        try        {            Class.forName(DBDRIVER);            try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);                    PreparedStatement pstmt = conn.prepareStatement(                            "INSERT INTO _1033 SET F01 = ?, F02 =? ON DUPLICATE KEY UPDATE F02 = VALUES(F02)"))            {                pstmt.setLong(1, 1);                pstmt.setString(2, "2");                pstmt.executeUpdate();            }            catch (Exception e)            {                e.printStackTrace();            }        }        catch (ClassNotFoundException e)        {            e.printStackTrace();        }    }}

異常資訊為

java.sql.SQLException: java.lang.StringIndexOutOfBoundsException: String index out of range: -36at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:904)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:894)at com.mysql.jdbc.Util.handleNewInstance(Util.java:418)at com.mysql.jdbc.PreparedStatement.getInstance(PreparedStatement.java:762)at com.mysql.jdbc.ConnectionImpl.clientPrepareStatement(ConnectionImpl.java:1455)at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4205)at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4109)at org.querydemo.QueryDemo.main(QueryDemo.java:22)Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -36at java.lang.String.substring(String.java:1911)at com.mysql.jdbc.PreparedStatement$ParseInfo.extractValuesClause(PreparedStatement.java:442)at com.mysql.jdbc.PreparedStatement$ParseInfo.buildRewriteBatchedParams(PreparedStatement.java:371)at com.mysql.jdbc.PreparedStatement$ParseInfo.<init>(PreparedStatement.java:358)at com.mysql.jdbc.PreparedStatement$ParseInfo.<init>(PreparedStatement.java:175)at com.mysql.jdbc.PreparedStatement.<init>(PreparedStatement.java:836)at com.mysql.jdbc.JDBC4PreparedStatement.<init>(JDBC4PreparedStatement.java:45)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:526)at com.mysql.jdbc.Util.handleNewInstance(Util.java:400)... 5 more

跟蹤代碼,發現MySQL的驅動程式在開啟 RewriteBatchedStatements 屬性後,會對滿足如下條件的SQL進行重寫

protected static boolean canRewrite(String sql, boolean isOnDuplicateKeyUpdate, int locationOfOnDuplicateKeyUpdate, int statementStartPos){  boolean rewritableOdku = true;    if (isOnDuplicateKeyUpdate) {    int updateClausePos = StringUtils.indexOfIgnoreCase(locationOfOnDuplicateKeyUpdate, sql, " UPDATE ");        if (updateClausePos != -1) {      rewritableOdku = StringUtils.indexOfIgnoreCase(updateClausePos, sql, "LAST_INSERT_ID", "\"‘`", "\"‘`", StringUtils.SEARCH_MODE__MRK_COM_WS) == -1;    }  }    return (StringUtils.startsWithIgnoreCaseAndWs(sql, "INSERT", statementStartPos)) && (StringUtils.indexOfIgnoreCase(statementStartPos, sql, "SELECT", "\"‘`", "\"‘`", StringUtils.SEARCH_MODE__MRK_COM_WS) == -1) && (rewritableOdku);}

重寫的方法可以參考com.mysql.jdbc.PreparedStatement類的下面兩個方法

private void buildRewriteBatchedParams(String sql, MySQLConnection conn, DatabaseMetaData metadata, String encoding, SingleByteCharsetConverter converter)private String extractValuesClause(String sql, String quoteCharStr) throws SQLException


【問題解決】:

修正的措施是將

PreparedStatement pstmt = conn.prepareStatement("INSERT INTO _1033 SET F01 = ?, F02 =? ON DUPLICATE KEY UPDATE F02 = VALUES(F02)")

改為

PreparedStatement pstmt = conn.prepareStatement("INSERT INTO _1033 (F01, F02 ) VALUES (?, ?) ON DUPLICATE KEY UPDATE F02 = VALUES(F02)")


本文出自 “技術點滴” 部落格,請務必保留此出處http://wangzhichao.blog.51cto.com/2643325/1687940

MySQL開啟RewriteBatchedStatements後PreparedStatement的一個異常

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.