{"id":10008226,"date":"2023-09-04T17:54:01","date_gmt":"2023-09-04T09:54:01","guid":{"rendered":"https:\/\/blog.itmax.cn\/?p=10008226"},"modified":"2023-09-04T17:54:01","modified_gmt":"2023-09-04T09:54:01","slug":"%e8%81%8a%e8%81%8amysql-jdbc%e7%9a%84preparestatement","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10008226","title":{"rendered":"\u804a\u804amysql jdbc\u7684prepareStatement"},"content":{"rendered":"<h2>\u5e8f<\/h2>\n<p>\u672c\u6587\u4e3b\u8981\u7814\u7a76\u4e00\u4e0bmysql jdbc\u7684prepareStatement<\/p>\n<h2>prepareStatement<\/h2>\n<p>java\/sql\/Connection.java<\/p>\n<pre><code>    \/**\n     * Creates a &lt;code&gt;PreparedStatement&lt;\/code&gt; object for sending\n     * parameterized SQL statements to the database.\n     * &lt;P&gt;\n     * A SQL statement with or without IN parameters can be\n     * pre-compiled and stored in a &lt;code&gt;PreparedStatement&lt;\/code&gt; object. This\n     * object can then be used to efficiently execute this statement\n     * multiple times.\n     *\n     * &lt;P&gt;&lt;B&gt;Note:&lt;\/B&gt; This method is optimized for handling\n     * parametric SQL statements that benefit from precompilation. If\n     * the driver supports precompilation,\n     * the method &lt;code&gt;prepareStatement&lt;\/code&gt; will send\n     * the statement to the database for precompilation. Some drivers\n     * may not support precompilation. In this case, the statement may\n     * not be sent to the database until the &lt;code&gt;PreparedStatement&lt;\/code&gt;\n     * object is executed.  This has no direct effect on users; however, it does\n     * affect which methods throw certain &lt;code&gt;SQLException&lt;\/code&gt; objects.\n     * &lt;P&gt;\n     * Result sets created using the returned &lt;code&gt;PreparedStatement&lt;\/code&gt;\n     * object will by default be type &lt;code&gt;TYPE_FORWARD_ONLY&lt;\/code&gt;\n     * and have a concurrency level of &lt;code&gt;CONCUR_READ_ONLY&lt;\/code&gt;.\n     * The holdability of the created result sets can be determined by\n     * calling {@link #getHoldability}.\n     *\n     * @param sql an SQL statement that may contain one or more '?' IN\n     * parameter placeholders\n     * @return a new default &lt;code&gt;PreparedStatement&lt;\/code&gt; object containing the\n     * pre-compiled SQL statement\n     * @exception SQLException if a database access error occurs\n     * or this method is called on a closed connection\n     *\/\n    PreparedStatement prepareStatement(String sql)\n        throws SQLException;<\/code><\/pre>\n<blockquote><p>java.sql.Connection\u5b9a\u4e49\u4e86prepareStatement\u65b9\u6cd5\uff0c\u6839\u636esql\u521b\u5efaPreparedStatement<\/p><\/blockquote>\n<h2>ConnectionImpl<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/ConnectionImpl.java<\/p>\n<pre><code>    \/**\n     * A SQL statement with or without IN parameters can be pre-compiled and\n     * stored in a PreparedStatement object. This object can then be used to\n     * efficiently execute this statement multiple times.\n     * &lt;p&gt;\n     * &lt;B&gt;Note:&lt;\/B&gt; This method is optimized for handling parametric SQL\n     * statements that benefit from precompilation if the driver supports\n     * precompilation. In this case, the statement is not sent to the database\n     * until the PreparedStatement is executed. This has no direct effect on\n     * users; however it does affect which method throws certain\n     * java.sql.SQLExceptions\n     * &lt;\/p&gt;\n     * &lt;p&gt;\n     * MySQL does not support precompilation of statements, so they are handled\n     * by the driver.\n     * &lt;\/p&gt;\n     * \n     * @param sql\n     *            a SQL statement that may contain one or more '?' IN parameter\n     *            placeholders\n     * @return a new PreparedStatement object containing the pre-compiled\n     *         statement.\n     * @exception SQLException\n     *                if a database access error occurs.\n     *\/\n    public java.sql.PreparedStatement prepareStatement(String sql)\n            throws SQLException {\n        return prepareStatement(sql, DEFAULT_RESULT_SET_TYPE,\n                DEFAULT_RESULT_SET_CONCURRENCY);\n    }<\/code><\/pre>\n<blockquote><p>mysql jdbc\u7684ConnectionImpl\u5b9e\u73b0\u4e86prepareStatement\u65b9\u6cd5\uff0c\u6839\u636e\u6ce8\u91ca\uff0c\u9884\u7f16\u8bd1\u4e3b\u8981\u662fdriver\u6765\u5904\u7406<\/p><\/blockquote>\n<h2>prepareStatement<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/ConnectionImpl.java<\/p>\n<pre><code>    \/**\n     * JDBC 2.0 Same as prepareStatement() above, but allows the default result\n     * set type and result set concurrency type to be overridden.\n     * \n     * @param sql\n     *            the SQL query containing place holders\n     * @param resultSetType\n     *            a result set type, see ResultSet.TYPE_XXX\n     * @param resultSetConcurrency\n     *            a concurrency type, see ResultSet.CONCUR_XXX\n     * @return a new PreparedStatement object containing the pre-compiled SQL\n     *         statement\n     * @exception SQLException\n     *                if a database-access error occurs.\n     *\/\n    public synchronized java.sql.PreparedStatement prepareStatement(String sql,\n            int resultSetType, int resultSetConcurrency) throws SQLException {\n        checkClosed();\n\n        \/\/\n        \/\/ FIXME: Create warnings if can't create results of the given\n        \/\/ type or concurrency\n        \/\/\n        PreparedStatement pStmt = null;\n        \n        boolean canServerPrepare = true;\n        \n        String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql;\n        \n        if (this.useServerPreparedStmts &amp;&amp; getEmulateUnsupportedPstmts()) {\n            canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);\n        }\n        \n        if (this.useServerPreparedStmts &amp;&amp; canServerPrepare) {\n            if (this.getCachePreparedStatements()) {\n                synchronized (this.serverSideStatementCache) {\n                    pStmt = (com.mysql.jdbc.ServerPreparedStatement)this.serverSideStatementCache.remove(sql);\n                    \n                    if (pStmt != null) {\n                        ((com.mysql.jdbc.ServerPreparedStatement)pStmt).setClosed(false);\n                        pStmt.clearParameters();\n                    }\n\n                    if (pStmt == null) {\n                        try {\n                            pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,\n                                    this.database, resultSetType, resultSetConcurrency);\n                            if (sql.length() &lt; getPreparedStatementCacheSqlLimit()) {\n                                ((com.mysql.jdbc.ServerPreparedStatement)pStmt).isCached = true;\n                            }\n                            \n                            pStmt.setResultSetType(resultSetType);\n                            pStmt.setResultSetConcurrency(resultSetConcurrency);\n                        } catch (SQLException sqlEx) {\n                            \/\/ Punt, if necessary\n                            if (getEmulateUnsupportedPstmts()) {\n                                pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);\n                                \n                                if (sql.length() &lt; getPreparedStatementCacheSqlLimit()) {\n                                    this.serverSideStatementCheckCache.put(sql, Boolean.FALSE);\n                                }\n                            } else {\n                                throw sqlEx;\n                            }\n                        }\n                    }\n                }\n            } else {\n                try {\n                    pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,\n                            this.database, resultSetType, resultSetConcurrency);\n                    \n                    pStmt.setResultSetType(resultSetType);\n                    pStmt.setResultSetConcurrency(resultSetConcurrency);\n                } catch (SQLException sqlEx) {\n                    \/\/ Punt, if necessary\n                    if (getEmulateUnsupportedPstmts()) {\n                        pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);\n                    } else {\n                        throw sqlEx;\n                    }\n                }\n            }\n        } else {\n            pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);\n        }\n        \n        return pStmt;\n    }<\/code><\/pre>\n<blockquote><p>prepareStatement\u9996\u5148\u6839\u636euseServerPreparedStmts\u4ee5\u53cagetEmulateUnsupportedPstmts\u6765\u5224\u65ad\u662f\u5426\u8981\u901a\u8fc7canHandleAsServerPreparedStatement\u5224\u65adcanServerPrepare\uff1b\u4e4b\u540e\u5728useServerPreparedStmts\u53cacanServerPrepare\u4e3atrue\u65f6\uff0c\u6839\u636ecachePreparedStatements\u505aServerPreparedStatement\u7684\u5904\u7406\uff1b\u5982\u679c\u4e0d\u5f00\u542fserverPrepare\u5219\u6267\u884cclientPrepareStatement<\/p><\/blockquote>\n<h2>canHandleAsServerPreparedStatement<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/ConnectionImpl.java<\/p>\n<pre><code>    private boolean canHandleAsServerPreparedStatement(String sql) \n        throws SQLException {\n        if (sql == null || sql.length() == 0) {\n            return true;\n        }\n\n        if (!this.useServerPreparedStmts) {\n            return false;\n        }\n        \n        if (getCachePreparedStatements()) {\n            synchronized (this.serverSideStatementCheckCache) {\n                Boolean flag = (Boolean)this.serverSideStatementCheckCache.get(sql);\n                \n                if (flag != null) {\n                    return flag.booleanValue();\n                }\n                    \n                boolean canHandle = canHandleAsServerPreparedStatementNoCache(sql);\n                \n                if (sql.length() &lt; getPreparedStatementCacheSqlLimit()) {\n                    this.serverSideStatementCheckCache.put(sql, \n                            canHandle ? Boolean.TRUE : Boolean.FALSE);\n                }\n                    \n                return canHandle;\n            }\n        }\n        \n        return canHandleAsServerPreparedStatementNoCache(sql);\n    }<\/code><\/pre>\n<blockquote><p>canHandleAsServerPreparedStatement\u9996\u5148\u5224\u65aduseServerPreparedStmts\uff0c\u4e4b\u540e\u82e5cachePreparedStatements\u4e3atrue\u5219\u505aserverSideStatementCheckCache\u5224\u65ad\uff0c\u6700\u540e\u90fd\u4f1a\u901a\u8fc7canHandleAsServerPreparedStatementNoCache\u8fdb\u884c\u5224\u65ad<\/p><\/blockquote>\n<h2>canHandleAsServerPreparedStatementNoCache<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/ConnectionImpl.java<\/p>\n<pre><code>    private boolean canHandleAsServerPreparedStatementNoCache(String sql) \n        throws SQLException {\n        \n        \/\/ Can't use server-side prepare for CALL\n        if (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, &quot;CALL&quot;)) {\n            return false;\n        }\n        \n        boolean canHandleAsStatement = true;\n        \n        if (!versionMeetsMinimum(5, 0, 7) &amp;&amp; \n                (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, &quot;SELECT&quot;)\n                || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,\n                        &quot;DELETE&quot;)\n                || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,\n                        &quot;INSERT&quot;)\n                || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,\n                        &quot;UPDATE&quot;)\n                || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,\n                        &quot;REPLACE&quot;))) {\n\n            \/\/ check for limit ?[,?]\n\n            \/*\n             * The grammar for this (from the server) is: ULONG_NUM | ULONG_NUM\n             * ',' ULONG_NUM | ULONG_NUM OFFSET_SYM ULONG_NUM\n             *\/\n\n            int currentPos = 0;\n            int statementLength = sql.length();\n            int lastPosToLook = statementLength - 7; \/\/ &quot;LIMIT &quot;.length()\n            boolean allowBackslashEscapes = !this.noBackslashEscapes;\n            char quoteChar = this.useAnsiQuotes ? '&quot;' : '\/'';\n            boolean foundLimitWithPlaceholder = false;\n\n            while (currentPos &lt; lastPosToLook) {\n                int limitStart = StringUtils.indexOfIgnoreCaseRespectQuotes(\n                        currentPos, sql, &quot;LIMIT &quot;, quoteChar,\n                        allowBackslashEscapes);\n\n                if (limitStart == -1) {\n                    break;\n                }\n\n                currentPos = limitStart + 7;\n\n                while (currentPos &lt; statementLength) {\n                    char c = sql.charAt(currentPos);\n\n                    \/\/\n                    \/\/ Have we reached the end\n                    \/\/ of what can be in a LIMIT clause?\n                    \/\/\n\n                    if (!Character.isDigit(c) &amp;&amp; !Character.isWhitespace(c)\n                            &amp;&amp; c != ',' &amp;&amp; c != '?') {\n                        break;\n                    }\n\n                    if (c == '?') {\n                        foundLimitWithPlaceholder = true;\n                        break;\n                    }\n\n                    currentPos++;\n                }\n            }\n\n            canHandleAsStatement = !foundLimitWithPlaceholder;\n        } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, &quot;CREATE TABLE&quot;)) {\n            canHandleAsStatement = false;\n        } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, &quot;DO&quot;)) {\n            canHandleAsStatement = false;\n        } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, &quot;SET&quot;)) {\n            canHandleAsStatement = false;\n        }\n\n        \n        \n        return canHandleAsStatement;\n    }<\/code><\/pre>\n<blockquote><p>canHandleAsServerPreparedStatementNoCache\u65b9\u6cd5\u9488\u5bf9call\u3001create table\u3001do\u3001set\u8fd4\u56defalse\uff0c\u5176\u4ed6\u7684\u9488\u5bf9\u5c0f\u4e8e5.0.7\u7248\u672c\u7684\u505a\u7279\u6b8a\u5224\u65ad\uff0c\u5176\u4f59\u7684\u9ed8\u8ba4\u8fd4\u56detrue<\/p><\/blockquote>\n<h2>clientPrepareStatement<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/ConnectionImpl.java<\/p>\n<pre><code>    \/** A cache of SQL to parsed prepared statement parameters. *\/\n    private CacheAdapter&lt;String, ParseInfo&gt; cachedPreparedStatementParams;\n\n    public java.sql.PreparedStatement clientPrepareStatement(String sql,\n            int resultSetType, int resultSetConcurrency, \n            boolean processEscapeCodesIfNeeded) throws SQLException {\n        checkClosed();\n\n        String nativeSql = processEscapeCodesIfNeeded &amp;&amp; getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql;\n        \n        PreparedStatement pStmt = null;\n\n        if (getCachePreparedStatements()) {\n            PreparedStatement.ParseInfo pStmtInfo = this.cachedPreparedStatementParams.get(nativeSql);\n \n            if (pStmtInfo == null) {\n                pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,\n                        this.database);\n\n                this.cachedPreparedStatementParams.put(nativeSql, pStmt\n                            .getParseInfo());\n            } else {\n                pStmt = new com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,\n                        this.database, pStmtInfo);\n            }\n        } else {\n            pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,\n                    this.database);\n        }\n\n        pStmt.setResultSetType(resultSetType);\n        pStmt.setResultSetConcurrency(resultSetConcurrency);\n\n        return pStmt;\n    }<\/code><\/pre>\n<blockquote><p>clientPrepareStatement\u5728cachePreparedStatements\u4e3atrue\u65f6\u4f1a\u4ececachedPreparedStatementParams(<code>\u7f13\u5b58\u7684key\u4e3anativeSql\uff0cvalue\u4e3aParseInfo<\/code>)\u53bb\u83b7\u53d6ParseInfo\uff0c\u83b7\u53d6\u4e0d\u5230\u5219\u6267\u884ccom.mysql.jdbc.PreparedStatement.getInstance\u518d\u653e\u5165\u7f13\u5b58\uff0c\u83b7\u53d6\u5230ParseInfo\u5219\u901a\u8fc7com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,this.database, pStmtInfo)\u521b\u5efaPreparedStatement\uff1b\u5982\u679c\u4e3afalse\u5219\u76f4\u63a5\u901a\u8fc7com.mysql.jdbc.PreparedStatement.getInstance\u6765\u521b\u5efa<\/p><\/blockquote>\n<h2>PreparedStatement.getInstance<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/PreparedStatement.java<\/p>\n<pre><code>    \/**\n     * Creates a prepared statement instance -- We need to provide factory-style\n     * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,\n     * otherwise the class verifier complains when it tries to load JDBC4-only\n     * interface classes that are present in JDBC4 method signatures.\n     *\/\n\n    protected static PreparedStatement getInstance(MySQLConnection conn, String sql,\n            String catalog) throws SQLException {\n        if (!Util.isJdbc4()) {\n            return new PreparedStatement(conn, sql, catalog);\n        }\n\n        return (PreparedStatement) Util.handleNewInstance(\n                JDBC_4_PSTMT_3_ARG_CTOR, new Object[] { conn, sql, catalog }, conn.getExceptionInterceptor());\n    }<\/code><\/pre>\n<blockquote><p>getInstance\u65b9\u6cd5\u5bf9\u4e8e\u975ejdbc4\u7684\u76f4\u63a5new\u4e00\u4e2aPreparedStatement\uff0c\u82e5\u4f7f\u7528\u4e86jdbc4\u5219\u901a\u8fc7Util.handleNewInstance\u4f7f\u7528JDBC_4_PSTMT_3_ARG_CTOR\u7684\u6784\u9020\u5668\u53cd\u5c04\u521b\u5efa<\/p><\/blockquote>\n<h2>JDBC_4_PSTMT_3_ARG_CTOR<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/PreparedStatement.java<\/p>\n<pre><code>public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements\n        java.sql.PreparedStatement {\n    private static final Constructor&lt;?&gt; JDBC_4_PSTMT_2_ARG_CTOR;\n    private static final Constructor&lt;?&gt; JDBC_4_PSTMT_3_ARG_CTOR;\n    private static final Constructor&lt;?&gt; JDBC_4_PSTMT_4_ARG_CTOR;\n    \n    static {\n        if (Util.isJdbc4()) {\n            try {\n                JDBC_4_PSTMT_2_ARG_CTOR = Class.forName(\n                        &quot;com.mysql.jdbc.JDBC4PreparedStatement&quot;)\n                        .getConstructor(\n                                new Class[] { MySQLConnection.class, String.class });\n                JDBC_4_PSTMT_3_ARG_CTOR = Class.forName(\n                        &quot;com.mysql.jdbc.JDBC4PreparedStatement&quot;)\n                        .getConstructor(\n                                new Class[] { MySQLConnection.class, String.class,\n                                        String.class });\n                JDBC_4_PSTMT_4_ARG_CTOR = Class.forName(\n                        &quot;com.mysql.jdbc.JDBC4PreparedStatement&quot;)\n                        .getConstructor(\n                                new Class[] { MySQLConnection.class, String.class,\n                                        String.class, ParseInfo.class });\n            } catch (SecurityException e) {\n                throw new RuntimeException(e);\n            } catch (NoSuchMethodException e) {\n                throw new RuntimeException(e);\n            } catch (ClassNotFoundException e) {\n                throw new RuntimeException(e);\n            }\n        } else {\n            JDBC_4_PSTMT_2_ARG_CTOR = null;\n            JDBC_4_PSTMT_3_ARG_CTOR = null;\n            JDBC_4_PSTMT_4_ARG_CTOR = null;\n        }\n    }\n\n    \/\/......\n}    <\/code><\/pre>\n<blockquote><p>com.mysql.jdbc.PreparedStatement\u5728static\u65b9\u6cd5\u521d\u59cb\u5316\u4e86JDBC_4_PSTMT_3_ARG_CTOR\uff0c\u5176\u6784\u9020\u5668\u6709\u4e09\u4e2a\u53c2\u6570\uff0c\u5206\u522b\u662fMySQLConnection.class, String.class,String.class\uff0c\u4f7f\u7528\u7684\u7c7b\u662fcom.mysql.jdbc.JDBC4PreparedStatement<\/p><\/blockquote>\n<h2>JDBC4PreparedStatement<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/JDBC4PreparedStatement.java<\/p>\n<pre><code>public class JDBC4PreparedStatement extends PreparedStatement {\n\n    public JDBC4PreparedStatement(MySQLConnection conn, String catalog) throws SQLException {\n        super(conn, catalog);\n    }\n    \n    public JDBC4PreparedStatement(MySQLConnection conn, String sql, String catalog)\n        throws SQLException {\n        super(conn, sql, catalog);\n    }\n    \n    public JDBC4PreparedStatement(MySQLConnection conn, String sql, String catalog,\n            ParseInfo cachedParseInfo) throws SQLException {\n        super(conn, sql, catalog, cachedParseInfo);\n    }\n\n    public void setRowId(int parameterIndex, RowId x) throws SQLException {\n        JDBC4PreparedStatementHelper.setRowId(this, parameterIndex, x);\n    }\n    \n    \/**\n     * JDBC 4.0 Set a NCLOB parameter.\n     * \n     * @param i\n     *            the first parameter is 1, the second is 2, ...\n     * @param x\n     *            an object representing a NCLOB\n     * \n     * @throws SQLException\n     *             if a database error occurs\n     *\/\n    public void setNClob(int parameterIndex, NClob value) throws SQLException {\n        JDBC4PreparedStatementHelper.setNClob(this, parameterIndex, value);\n    }\n\n    public void setSQLXML(int parameterIndex, SQLXML xmlObject)\n            throws SQLException {\n        JDBC4PreparedStatementHelper.setSQLXML(this, parameterIndex, xmlObject);\n    }\n}    <\/code><\/pre>\n<blockquote><p>JDBC4PreparedStatement\u7684\u4e09\u4e2a\u53c2\u6570\u6784\u9020\u5668\u4e3b\u8981\u662f\u8c03\u7528\u4e86\u7236\u7c7bPreparedStatement\u7684\u5bf9\u5e94\u7684\u6784\u9020\u5668\uff1bJDBC4PreparedStatement\u4e3b\u8981\u662f\u652f\u6301\u4e86setNClob\u3001setSQLXML<\/p><\/blockquote>\n<h2>new PreparedStatement<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/PreparedStatement.java<\/p>\n<pre><code>    \/**\n     * Constructor for the PreparedStatement class.\n     * \n     * @param conn\n     *            the connection creating this statement\n     * @param sql\n     *            the SQL for this statement\n     * @param catalog\n     *            the catalog\/database this statement should be issued against\n     * \n     * @throws SQLException\n     *             if a database error occurs.\n     *\/\n    public PreparedStatement(MySQLConnection conn, String sql, String catalog)\n            throws SQLException {\n        super(conn, catalog);\n\n        if (sql == null) {\n            throw SQLError.createSQLException(Messages.getString(&quot;PreparedStatement.0&quot;), \/\/$NON-NLS-1$\n                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());\n        }\n\n        detectFractionalSecondsSupport();\n        this.originalSql = sql;\n\n        if (this.originalSql.startsWith(PING_MARKER)) {\n            this.doPingInstead = true;\n        } else {\n            this.doPingInstead = false;\n        }\n        \n        this.dbmd = this.connection.getMetaData();\n\n        this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);\n\n        this.parseInfo = new ParseInfo(sql, this.connection, this.dbmd,\n                this.charEncoding, this.charConverter);\n\n        initializeFromParseInfo();\n        \n        this.compensateForOnDuplicateKeyUpdate = this.connection.getCompensateOnDuplicateKeyUpdateCounts();\n        \n        if (conn.getRequiresEscapingEncoder())\n            charsetEncoder = Charset.forName(conn.getEncoding()).newEncoder();\n    }<\/code><\/pre>\n<blockquote><p>\u8fd9\u91cc\u4e3b\u8981\u662f\u7528\u4e86connection\u7684metaData\u3001\u4ee5\u53ca\u6784\u9020ParseInfo<\/p><\/blockquote>\n<h2>StatementImpl<\/h2>\n<p>mysql-connector-java-5.1.21-sources.jar!\/com\/mysql\/jdbc\/StatementImpl.java<\/p>\n<pre><code>    public StatementImpl(MySQLConnection c, String catalog) throws SQLException {\n        if ((c == null) || c.isClosed()) {\n            throw SQLError.createSQLException(\n                    Messages.getString(&quot;Statement.0&quot;), \/\/$NON-NLS-1$\n                    SQLError.SQL_STATE_CONNECTION_NOT_OPEN, null); \/\/$NON-NLS-1$ \/\/$NON-NLS-2$\n        }\n\n        this.connection = c;\n        this.connectionId = this.connection.getId();\n        this.exceptionInterceptor = this.connection\n                .getExceptionInterceptor();\n\n        this.currentCatalog = catalog;\n        this.pedantic = this.connection.getPedantic();\n        this.continueBatchOnError = this.connection.getContinueBatchOnError();\n        this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode();\n        \n        if (!this.connection.getDontTrackOpenResources()) {\n            this.connection.registerStatement(this);\n        }\n\n        \/\/\n        \/\/ Adjust, if we know it\n        \/\/\n\n        if (this.connection != null) {\n            this.maxFieldSize = this.connection.getMaxAllowedPacket();\n\n            int defaultFetchSize = this.connection.getDefaultFetchSize();\n\n            if (defaultFetchSize != 0) {\n                setFetchSize(defaultFetchSize);\n            }\n            \n            if (this.connection.getUseUnicode()) {\n                this.charEncoding = this.connection.getEncoding();\n\n                this.charConverter = this.connection.getCharsetConverter(this.charEncoding);\n            }\n            \n            \n\n            boolean profiling = this.connection.getProfileSql()\n                    || this.connection.getUseUsageAdvisor() || this.connection.getLogSlowQueries();\n\n            if (this.connection.getAutoGenerateTestcaseScript() || profiling) {\n                this.statementId = statementCounter++;\n            }\n\n            if (profiling) {\n                this.pointOfOrigin = new Throwable();\n                this.profileSQL = this.connection.getProfileSql();\n                this.useUsageAdvisor = this.connection.getUseUsageAdvisor();\n                this.eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);\n            }\n\n            int maxRowsConn = this.connection.getMaxRows();\n\n            if (maxRowsConn != -1) {\n                setMaxRows(maxRowsConn);\n            }\n            \n            this.holdResultsOpenOverClose = this.connection.getHoldResultsOpenOverStatementClose();\n        }\n        \n        version5013OrNewer = this.connection.versionMeetsMinimum(5, 0, 13);\n    }<\/code><\/pre>\n<blockquote><p>\u8fd9\u91cc\u4f1a\u83b7\u53d6connection\u7684\u4e00\u7cfb\u5217\u914d\u7f6e\uff0c\u540c\u65f6\u5bf9\u4e8e\u9700\u8981trackOpenResources\u7684\u4f1a\u6267\u884cregisterStatement(<code>\u8fd9\u4e2a\u5728realClose\u7684\u65f6\u5019\u4f1aunregister<\/code>)<\/p><\/blockquote>\n<h2>\u53c2\u6570\u503c<\/h2>\n<h3>isJdbc4<\/h3>\n<p>com\/mysql\/jdbc\/Util.java<\/p>\n<pre><code>private static boolean isJdbc4 = false;\n\n        try {\n            Class.forName(&quot;java.sql.NClob&quot;);\n            isJdbc4 = true;\n        } catch (Throwable t) {\n            isJdbc4 = false;\n        }<\/code><\/pre>\n<blockquote><p>isJdbc4\u9ed8\u8ba4\u4e3afalse\uff0c\u5728\u68c0\u6d4b\u5230java.sql.NClob\u7c7b\u7684\u65f6\u5019\u4e3atrue\uff1bjdk8\u7248\u672c\u652f\u6301jdbc4<\/p><\/blockquote>\n<h3>useServerPreparedStmts<\/h3>\n<p>com\/mysql\/jdbc\/ConnectionPropertiesImpl.java<\/p>\n<pre><code>    private BooleanConnectionProperty detectServerPreparedStmts = new BooleanConnectionProperty(\n            &quot;useServerPrepStmts&quot;, \/\/$NON-NLS-1$\n            false,\n            Messages.getString(&quot;ConnectionProperties.useServerPrepStmts&quot;), \/\/$NON-NLS-1$\n            &quot;3.1.0&quot;, MISC_CATEGORY, Integer.MIN_VALUE); \/\/$NON-NLS-1$<\/code><\/pre>\n<blockquote><p>useServerPreparedStmts\u9ed8\u8ba4\u4e3afalse<\/p><\/blockquote>\n<h3>cachePrepStmts<\/h3>\n<p>com\/mysql\/jdbc\/ConnectionPropertiesImpl.java<\/p>\n<pre><code>    private BooleanConnectionProperty cachePreparedStatements = new BooleanConnectionProperty(\n            &quot;cachePrepStmts&quot;, \/\/$NON-NLS-1$\n            false,\n            Messages.getString(&quot;ConnectionProperties.cachePrepStmts&quot;), \/\/$NON-NLS-1$\n            &quot;3.0.10&quot;, PERFORMANCE_CATEGORY, Integer.MIN_VALUE); \/\/$NON-NLS-1$<\/code><\/pre>\n<blockquote><p>cachePrepStmts\u9ed8\u8ba4\u4e3afalse<\/p><\/blockquote>\n<h2>\u5c0f\u7ed3<\/h2>\n<ul>\n<li>mysql\u7684jdbc driver\u7684prepareStatement\u9996\u5148\u6839\u636euseServerPreparedStmts\u4ee5\u53cagetEmulateUnsupportedPstmts\u6765\u5224\u65ad\u662f\u5426\u8981\u901a\u8fc7canHandleAsServerPreparedStatement\u5224\u65adcanServerPrepare\uff1b\u4e4b\u540e\u5728useServerPreparedStmts\u53cacanServerPrepare\u4e3atrue\u65f6\uff0c\u6839\u636ecachePreparedStatements\u505aServerPreparedStatement\u7684\u5904\u7406\uff1b\u5982\u679c\u4e0d\u5f00\u542fserverPrepare\u5219\u6267\u884cclientPrepareStatement(<code>useServerPreparedStmts\u53cacachePrepStmts\u53c2\u6570\u9ed8\u8ba4\u4e3afalse<\/code>)<\/li>\n<li>clientPrepareStatement\u5728cachePreparedStatements\u4e3atrue\u65f6\u4f1a\u4ececachedPreparedStatementParams(<code>\u7f13\u5b58\u7684key\u4e3anativeSql\uff0cvalue\u4e3aParseInfo<\/code>)\u53bb\u83b7\u53d6ParseInfo\uff0c\u83b7\u53d6\u4e0d\u5230\u5219\u6267\u884ccom.mysql.jdbc.PreparedStatement.getInstance\u518d\u653e\u5165\u7f13\u5b58\uff0c\u83b7\u53d6\u5230ParseInfo\u5219\u901a\u8fc7com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,this.database, pStmtInfo)\u521b\u5efaPreparedStatement\uff1b\u5982\u679c\u4e3afalse\u5219\u76f4\u63a5\u901a\u8fc7com.mysql.jdbc.PreparedStatement.getInstance\u6765\u521b\u5efa<\/li>\n<li>useServerPreparedStmts\u4e3atrue\u65f6\uff0c\u521b\u5efa\u7684\u662fServerPreparedStatement(<code>\u521b\u5efa\u7684\u65f6\u5019\u4f1a\u89e6\u53d1prepare\u64cd\u4f5c\uff0c\u5f80mysql\u670d\u52a1\u7aef\u53d1\u9001COM_PREPARE\u6307\u4ee4<\/code>)\uff0c\u672c\u5730\u901a\u8fc7serverSideStatementCache\u7c7b\u6765\u7f13\u5b58ServerPreparedStatement\uff0ckey\u4e3asql<\/li>\n<\/ul>\n<h2>doc<\/h2>\n<ul>\n<li><a target=\"_blank\" href=\"https:\/\/link.segmentfault.com\/?enc=Wv8G4sfeP6NykeWnXGu5Jw%3D%3D.7E%2FApMHj7ObaFfw3oiP2xgdPdkUMmq4AOFb27Rktz61rNh7PcpOp3xayNePjTAsg2LAvcM6mRdNgeZFSg9eL1w%3D%3D\" rel=\"noopener noreferrer\">\u9884\u7f16\u8bd1\u8bed\u53e5(Prepared Statements)\u4ecb\u7ecd\uff0c\u4ee5MySQL\u4e3a\u4f8b<\/a><\/li>\n<\/ul>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000044178735\">https:\/\/segmentfault.com\/a\/1190000044178735<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5e8f \u672c\u6587\u4e3b\u8981\u7814\u7a76\u4e00\u4e0bmysql jdbc\u7684prepareStatement prepareStatement  [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10008226","post","type-post","status-publish","format-standard","hentry","category-share"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10008226","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10008226"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10008226\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10008226"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10008226"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10008226"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}