美文网首页
聊聊mysql jdbc的prepareStatement

聊聊mysql jdbc的prepareStatement

作者: go4it | 来源:发表于2023-09-03 12:57 被阅读0次

    本文主要研究一下mysql jdbc的prepareStatement

    prepareStatement

    java/sql/Connection.java

        /**
         * Creates a <code>PreparedStatement</code> object for sending
         * parameterized SQL statements to the database.
         * <P>
         * A SQL statement with or without IN parameters can be
         * pre-compiled and stored in a <code>PreparedStatement</code> object. This
         * object can then be used to efficiently execute this statement
         * multiple times.
         *
         * <P><B>Note:</B> This method is optimized for handling
         * parametric SQL statements that benefit from precompilation. If
         * the driver supports precompilation,
         * the method <code>prepareStatement</code> will send
         * the statement to the database for precompilation. Some drivers
         * may not support precompilation. In this case, the statement may
         * not be sent to the database until the <code>PreparedStatement</code>
         * object is executed.  This has no direct effect on users; however, it does
         * affect which methods throw certain <code>SQLException</code> objects.
         * <P>
         * Result sets created using the returned <code>PreparedStatement</code>
         * object will by default be type <code>TYPE_FORWARD_ONLY</code>
         * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
         * The holdability of the created result sets can be determined by
         * calling {@link #getHoldability}.
         *
         * @param sql an SQL statement that may contain one or more '?' IN
         * parameter placeholders
         * @return a new default <code>PreparedStatement</code> object containing the
         * pre-compiled SQL statement
         * @exception SQLException if a database access error occurs
         * or this method is called on a closed connection
         */
        PreparedStatement prepareStatement(String sql)
            throws SQLException;
    

    java.sql.Connection定义了prepareStatement方法,根据sql创建PreparedStatement

    ConnectionImpl

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/ConnectionImpl.java

        /**
         * A SQL statement with or without IN parameters can be pre-compiled and
         * stored in a PreparedStatement object. This object can then be used to
         * efficiently execute this statement multiple times.
         * <p>
         * <B>Note:</B> This method is optimized for handling parametric SQL
         * statements that benefit from precompilation if the driver supports
         * precompilation. In this case, the statement is not sent to the database
         * until the PreparedStatement is executed. This has no direct effect on
         * users; however it does affect which method throws certain
         * java.sql.SQLExceptions
         * </p>
         * <p>
         * MySQL does not support precompilation of statements, so they are handled
         * by the driver.
         * </p>
         * 
         * @param sql
         *            a SQL statement that may contain one or more '?' IN parameter
         *            placeholders
         * @return a new PreparedStatement object containing the pre-compiled
         *         statement.
         * @exception SQLException
         *                if a database access error occurs.
         */
        public java.sql.PreparedStatement prepareStatement(String sql)
                throws SQLException {
            return prepareStatement(sql, DEFAULT_RESULT_SET_TYPE,
                    DEFAULT_RESULT_SET_CONCURRENCY);
        }
    

    mysql jdbc的ConnectionImpl实现了prepareStatement方法,根据注释,预编译主要是driver来处理

    prepareStatement

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/ConnectionImpl.java

        /**
         * JDBC 2.0 Same as prepareStatement() above, but allows the default result
         * set type and result set concurrency type to be overridden.
         * 
         * @param sql
         *            the SQL query containing place holders
         * @param resultSetType
         *            a result set type, see ResultSet.TYPE_XXX
         * @param resultSetConcurrency
         *            a concurrency type, see ResultSet.CONCUR_XXX
         * @return a new PreparedStatement object containing the pre-compiled SQL
         *         statement
         * @exception SQLException
         *                if a database-access error occurs.
         */
        public synchronized java.sql.PreparedStatement prepareStatement(String sql,
                int resultSetType, int resultSetConcurrency) throws SQLException {
            checkClosed();
    
            //
            // FIXME: Create warnings if can't create results of the given
            // type or concurrency
            //
            PreparedStatement pStmt = null;
            
            boolean canServerPrepare = true;
            
            String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql;
            
            if (this.useServerPreparedStmts && getEmulateUnsupportedPstmts()) {
                canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
            }
            
            if (this.useServerPreparedStmts && canServerPrepare) {
                if (this.getCachePreparedStatements()) {
                    synchronized (this.serverSideStatementCache) {
                        pStmt = (com.mysql.jdbc.ServerPreparedStatement)this.serverSideStatementCache.remove(sql);
                        
                        if (pStmt != null) {
                            ((com.mysql.jdbc.ServerPreparedStatement)pStmt).setClosed(false);
                            pStmt.clearParameters();
                        }
    
                        if (pStmt == null) {
                            try {
                                pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
                                        this.database, resultSetType, resultSetConcurrency);
                                if (sql.length() < getPreparedStatementCacheSqlLimit()) {
                                    ((com.mysql.jdbc.ServerPreparedStatement)pStmt).isCached = true;
                                }
                                
                                pStmt.setResultSetType(resultSetType);
                                pStmt.setResultSetConcurrency(resultSetConcurrency);
                            } catch (SQLException sqlEx) {
                                // Punt, if necessary
                                if (getEmulateUnsupportedPstmts()) {
                                    pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
                                    
                                    if (sql.length() < getPreparedStatementCacheSqlLimit()) {
                                        this.serverSideStatementCheckCache.put(sql, Boolean.FALSE);
                                    }
                                } else {
                                    throw sqlEx;
                                }
                            }
                        }
                    }
                } else {
                    try {
                        pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
                                this.database, resultSetType, resultSetConcurrency);
                        
                        pStmt.setResultSetType(resultSetType);
                        pStmt.setResultSetConcurrency(resultSetConcurrency);
                    } catch (SQLException sqlEx) {
                        // Punt, if necessary
                        if (getEmulateUnsupportedPstmts()) {
                            pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
                        } else {
                            throw sqlEx;
                        }
                    }
                }
            } else {
                pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
            }
            
            return pStmt;
        }
    

    prepareStatement首先根据useServerPreparedStmts以及getEmulateUnsupportedPstmts来判断是否要通过canHandleAsServerPreparedStatement判断canServerPrepare;之后在useServerPreparedStmts及canServerPrepare为true时,根据cachePreparedStatements做ServerPreparedStatement的处理;如果不开启serverPrepare则执行clientPrepareStatement

    canHandleAsServerPreparedStatement

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/ConnectionImpl.java

        private boolean canHandleAsServerPreparedStatement(String sql) 
            throws SQLException {
            if (sql == null || sql.length() == 0) {
                return true;
            }
    
            if (!this.useServerPreparedStmts) {
                return false;
            }
            
            if (getCachePreparedStatements()) {
                synchronized (this.serverSideStatementCheckCache) {
                    Boolean flag = (Boolean)this.serverSideStatementCheckCache.get(sql);
                    
                    if (flag != null) {
                        return flag.booleanValue();
                    }
                        
                    boolean canHandle = canHandleAsServerPreparedStatementNoCache(sql);
                    
                    if (sql.length() < getPreparedStatementCacheSqlLimit()) {
                        this.serverSideStatementCheckCache.put(sql, 
                                canHandle ? Boolean.TRUE : Boolean.FALSE);
                    }
                        
                    return canHandle;
                }
            }
            
            return canHandleAsServerPreparedStatementNoCache(sql);
        }
    

    canHandleAsServerPreparedStatement首先判断useServerPreparedStmts,之后若cachePreparedStatements为true则做serverSideStatementCheckCache判断,最后都会通过canHandleAsServerPreparedStatementNoCache进行判断

    canHandleAsServerPreparedStatementNoCache

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/ConnectionImpl.java

        private boolean canHandleAsServerPreparedStatementNoCache(String sql) 
            throws SQLException {
            
            // Can't use server-side prepare for CALL
            if (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "CALL")) {
                return false;
            }
            
            boolean canHandleAsStatement = true;
            
            if (!versionMeetsMinimum(5, 0, 7) && 
                    (StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql, "SELECT")
                    || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
                            "DELETE")
                    || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
                            "INSERT")
                    || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
                            "UPDATE")
                    || StringUtils.startsWithIgnoreCaseAndNonAlphaNumeric(sql,
                            "REPLACE"))) {
    
                // check for limit ?[,?]
    
                /*
                 * The grammar for this (from the server) is: ULONG_NUM | ULONG_NUM
                 * ',' ULONG_NUM | ULONG_NUM OFFSET_SYM ULONG_NUM
                 */
    
                int currentPos = 0;
                int statementLength = sql.length();
                int lastPosToLook = statementLength - 7; // "LIMIT ".length()
                boolean allowBackslashEscapes = !this.noBackslashEscapes;
                char quoteChar = this.useAnsiQuotes ? '"' : '\'';
                boolean foundLimitWithPlaceholder = false;
    
                while (currentPos < lastPosToLook) {
                    int limitStart = StringUtils.indexOfIgnoreCaseRespectQuotes(
                            currentPos, sql, "LIMIT ", quoteChar,
                            allowBackslashEscapes);
    
                    if (limitStart == -1) {
                        break;
                    }
    
                    currentPos = limitStart + 7;
    
                    while (currentPos < statementLength) {
                        char c = sql.charAt(currentPos);
    
                        //
                        // Have we reached the end
                        // of what can be in a LIMIT clause?
                        //
    
                        if (!Character.isDigit(c) && !Character.isWhitespace(c)
                                && c != ',' && c != '?') {
                            break;
                        }
    
                        if (c == '?') {
                            foundLimitWithPlaceholder = true;
                            break;
                        }
    
                        currentPos++;
                    }
                }
    
                canHandleAsStatement = !foundLimitWithPlaceholder;
            } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "CREATE TABLE")) {
                canHandleAsStatement = false;
            } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "DO")) {
                canHandleAsStatement = false;
            } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "SET")) {
                canHandleAsStatement = false;
            }
    
            
            
            return canHandleAsStatement;
        }
    

    canHandleAsServerPreparedStatementNoCache方法针对call、create table、do、set返回false,其他的针对小于5.0.7版本的做特殊判断,其余的默认返回true

    clientPrepareStatement

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/ConnectionImpl.java

        /** A cache of SQL to parsed prepared statement parameters. */
        private CacheAdapter<String, ParseInfo> cachedPreparedStatementParams;
    
        public java.sql.PreparedStatement clientPrepareStatement(String sql,
                int resultSetType, int resultSetConcurrency, 
                boolean processEscapeCodesIfNeeded) throws SQLException {
            checkClosed();
    
            String nativeSql = processEscapeCodesIfNeeded && getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql): sql;
            
            PreparedStatement pStmt = null;
    
            if (getCachePreparedStatements()) {
                PreparedStatement.ParseInfo pStmtInfo = this.cachedPreparedStatementParams.get(nativeSql);
     
                if (pStmtInfo == null) {
                    pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
                            this.database);
    
                    this.cachedPreparedStatementParams.put(nativeSql, pStmt
                                .getParseInfo());
                } else {
                    pStmt = new com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,
                            this.database, pStmtInfo);
                }
            } else {
                pStmt = com.mysql.jdbc.PreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
                        this.database);
            }
    
            pStmt.setResultSetType(resultSetType);
            pStmt.setResultSetConcurrency(resultSetConcurrency);
    
            return pStmt;
        }
    

    clientPrepareStatement在cachePreparedStatements为true时会从cachedPreparedStatementParams(缓存的key为nativeSql,value为ParseInfo)去获取ParseInfo,获取不到则执行com.mysql.jdbc.PreparedStatement.getInstance再放入缓存,获取到ParseInfo则通过com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,this.database, pStmtInfo)创建PreparedStatement;如果为false则直接通过com.mysql.jdbc.PreparedStatement.getInstance来创建

    PreparedStatement.getInstance

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/PreparedStatement.java

        /**
         * Creates a prepared statement instance -- We need to provide factory-style
         * methods so we can support both JDBC3 (and older) and JDBC4 runtimes,
         * otherwise the class verifier complains when it tries to load JDBC4-only
         * interface classes that are present in JDBC4 method signatures.
         */
    
        protected static PreparedStatement getInstance(MySQLConnection conn, String sql,
                String catalog) throws SQLException {
            if (!Util.isJdbc4()) {
                return new PreparedStatement(conn, sql, catalog);
            }
    
            return (PreparedStatement) Util.handleNewInstance(
                    JDBC_4_PSTMT_3_ARG_CTOR, new Object[] { conn, sql, catalog }, conn.getExceptionInterceptor());
        }
    

    getInstance方法对于非jdbc4的直接new一个PreparedStatement,若使用了jdbc4则通过Util.handleNewInstance使用JDBC_4_PSTMT_3_ARG_CTOR的构造器反射创建

    JDBC_4_PSTMT_3_ARG_CTOR

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/PreparedStatement.java

    public class PreparedStatement extends com.mysql.jdbc.StatementImpl implements
            java.sql.PreparedStatement {
        private static final Constructor<?> JDBC_4_PSTMT_2_ARG_CTOR;
        private static final Constructor<?> JDBC_4_PSTMT_3_ARG_CTOR;
        private static final Constructor<?> JDBC_4_PSTMT_4_ARG_CTOR;
        
        static {
            if (Util.isJdbc4()) {
                try {
                    JDBC_4_PSTMT_2_ARG_CTOR = Class.forName(
                            "com.mysql.jdbc.JDBC4PreparedStatement")
                            .getConstructor(
                                    new Class[] { MySQLConnection.class, String.class });
                    JDBC_4_PSTMT_3_ARG_CTOR = Class.forName(
                            "com.mysql.jdbc.JDBC4PreparedStatement")
                            .getConstructor(
                                    new Class[] { MySQLConnection.class, String.class,
                                            String.class });
                    JDBC_4_PSTMT_4_ARG_CTOR = Class.forName(
                            "com.mysql.jdbc.JDBC4PreparedStatement")
                            .getConstructor(
                                    new Class[] { MySQLConnection.class, String.class,
                                            String.class, ParseInfo.class });
                } catch (SecurityException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            } else {
                JDBC_4_PSTMT_2_ARG_CTOR = null;
                JDBC_4_PSTMT_3_ARG_CTOR = null;
                JDBC_4_PSTMT_4_ARG_CTOR = null;
            }
        }
    
        //......
    }   
    

    com.mysql.jdbc.PreparedStatement在static方法初始化了JDBC_4_PSTMT_3_ARG_CTOR,其构造器有三个参数,分别是MySQLConnection.class, String.class,String.class,使用的类是com.mysql.jdbc.JDBC4PreparedStatement

    JDBC4PreparedStatement

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/JDBC4PreparedStatement.java

    public class JDBC4PreparedStatement extends PreparedStatement {
    
        public JDBC4PreparedStatement(MySQLConnection conn, String catalog) throws SQLException {
            super(conn, catalog);
        }
        
        public JDBC4PreparedStatement(MySQLConnection conn, String sql, String catalog)
            throws SQLException {
            super(conn, sql, catalog);
        }
        
        public JDBC4PreparedStatement(MySQLConnection conn, String sql, String catalog,
                ParseInfo cachedParseInfo) throws SQLException {
            super(conn, sql, catalog, cachedParseInfo);
        }
    
        public void setRowId(int parameterIndex, RowId x) throws SQLException {
            JDBC4PreparedStatementHelper.setRowId(this, parameterIndex, x);
        }
        
        /**
         * JDBC 4.0 Set a NCLOB parameter.
         * 
         * @param i
         *            the first parameter is 1, the second is 2, ...
         * @param x
         *            an object representing a NCLOB
         * 
         * @throws SQLException
         *             if a database error occurs
         */
        public void setNClob(int parameterIndex, NClob value) throws SQLException {
            JDBC4PreparedStatementHelper.setNClob(this, parameterIndex, value);
        }
    
        public void setSQLXML(int parameterIndex, SQLXML xmlObject)
                throws SQLException {
            JDBC4PreparedStatementHelper.setSQLXML(this, parameterIndex, xmlObject);
        }
    }   
    

    JDBC4PreparedStatement的三个参数构造器主要是调用了父类PreparedStatement的对应的构造器;JDBC4PreparedStatement主要是支持了setNClob、setSQLXML

    new PreparedStatement

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/PreparedStatement.java

        /**
         * Constructor for the PreparedStatement class.
         * 
         * @param conn
         *            the connection creating this statement
         * @param sql
         *            the SQL for this statement
         * @param catalog
         *            the catalog/database this statement should be issued against
         * 
         * @throws SQLException
         *             if a database error occurs.
         */
        public PreparedStatement(MySQLConnection conn, String sql, String catalog)
                throws SQLException {
            super(conn, catalog);
    
            if (sql == null) {
                throw SQLError.createSQLException(Messages.getString("PreparedStatement.0"), //$NON-NLS-1$
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
            }
    
            detectFractionalSecondsSupport();
            this.originalSql = sql;
    
            if (this.originalSql.startsWith(PING_MARKER)) {
                this.doPingInstead = true;
            } else {
                this.doPingInstead = false;
            }
            
            this.dbmd = this.connection.getMetaData();
    
            this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23);
    
            this.parseInfo = new ParseInfo(sql, this.connection, this.dbmd,
                    this.charEncoding, this.charConverter);
    
            initializeFromParseInfo();
            
            this.compensateForOnDuplicateKeyUpdate = this.connection.getCompensateOnDuplicateKeyUpdateCounts();
            
            if (conn.getRequiresEscapingEncoder())
                charsetEncoder = Charset.forName(conn.getEncoding()).newEncoder();
        }
    

    这里主要是用了connection的metaData、以及构造ParseInfo

    StatementImpl

    mysql-connector-java-5.1.21-sources.jar!/com/mysql/jdbc/StatementImpl.java

        public StatementImpl(MySQLConnection c, String catalog) throws SQLException {
            if ((c == null) || c.isClosed()) {
                throw SQLError.createSQLException(
                        Messages.getString("Statement.0"), //$NON-NLS-1$
                        SQLError.SQL_STATE_CONNECTION_NOT_OPEN, null); //$NON-NLS-1$ //$NON-NLS-2$
            }
    
            this.connection = c;
            this.connectionId = this.connection.getId();
            this.exceptionInterceptor = this.connection
                    .getExceptionInterceptor();
    
            this.currentCatalog = catalog;
            this.pedantic = this.connection.getPedantic();
            this.continueBatchOnError = this.connection.getContinueBatchOnError();
            this.useLegacyDatetimeCode = this.connection.getUseLegacyDatetimeCode();
            
            if (!this.connection.getDontTrackOpenResources()) {
                this.connection.registerStatement(this);
            }
    
            //
            // Adjust, if we know it
            //
    
            if (this.connection != null) {
                this.maxFieldSize = this.connection.getMaxAllowedPacket();
    
                int defaultFetchSize = this.connection.getDefaultFetchSize();
    
                if (defaultFetchSize != 0) {
                    setFetchSize(defaultFetchSize);
                }
                
                if (this.connection.getUseUnicode()) {
                    this.charEncoding = this.connection.getEncoding();
    
                    this.charConverter = this.connection.getCharsetConverter(this.charEncoding);
                }
                
                
    
                boolean profiling = this.connection.getProfileSql()
                        || this.connection.getUseUsageAdvisor() || this.connection.getLogSlowQueries();
    
                if (this.connection.getAutoGenerateTestcaseScript() || profiling) {
                    this.statementId = statementCounter++;
                }
    
                if (profiling) {
                    this.pointOfOrigin = new Throwable();
                    this.profileSQL = this.connection.getProfileSql();
                    this.useUsageAdvisor = this.connection.getUseUsageAdvisor();
                    this.eventSink = ProfilerEventHandlerFactory.getInstance(this.connection);
                }
    
                int maxRowsConn = this.connection.getMaxRows();
    
                if (maxRowsConn != -1) {
                    setMaxRows(maxRowsConn);
                }
                
                this.holdResultsOpenOverClose = this.connection.getHoldResultsOpenOverStatementClose();
            }
            
            version5013OrNewer = this.connection.versionMeetsMinimum(5, 0, 13);
        }
    

    这里会获取connection的一系列配置,同时对于需要trackOpenResources的会执行registerStatement(这个在realClose的时候会unregister)

    参数值

    isJdbc4

    com/mysql/jdbc/Util.java

    private static boolean isJdbc4 = false;
    
            try {
                Class.forName("java.sql.NClob");
                isJdbc4 = true;
            } catch (Throwable t) {
                isJdbc4 = false;
            }
    

    isJdbc4默认为false,在检测到java.sql.NClob类的时候为true;jdk8版本支持jdbc4

    useServerPreparedStmts

    com/mysql/jdbc/ConnectionPropertiesImpl.java

        private BooleanConnectionProperty detectServerPreparedStmts = new BooleanConnectionProperty(
                "useServerPrepStmts", //$NON-NLS-1$
                false,
                Messages.getString("ConnectionProperties.useServerPrepStmts"), //$NON-NLS-1$
                "3.1.0", MISC_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
    

    useServerPreparedStmts默认为false

    cachePrepStmts

    com/mysql/jdbc/ConnectionPropertiesImpl.java

        private BooleanConnectionProperty cachePreparedStatements = new BooleanConnectionProperty(
                "cachePrepStmts", //$NON-NLS-1$
                false,
                Messages.getString("ConnectionProperties.cachePrepStmts"), //$NON-NLS-1$
                "3.0.10", PERFORMANCE_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
    

    cachePrepStmts默认为false

    小结

    • mysql的jdbc driver的prepareStatement首先根据useServerPreparedStmts以及getEmulateUnsupportedPstmts来判断是否要通过canHandleAsServerPreparedStatement判断canServerPrepare;之后在useServerPreparedStmts及canServerPrepare为true时,根据cachePreparedStatements做ServerPreparedStatement的处理;如果不开启serverPrepare则执行clientPrepareStatement(useServerPreparedStmts及cachePrepStmts参数默认为false)
    • clientPrepareStatement在cachePreparedStatements为true时会从cachedPreparedStatementParams(缓存的key为nativeSql,value为ParseInfo)去获取ParseInfo,获取不到则执行com.mysql.jdbc.PreparedStatement.getInstance再放入缓存,获取到ParseInfo则通过com.mysql.jdbc.PreparedStatement(getLoadBalanceSafeProxy(), nativeSql,this.database, pStmtInfo)创建PreparedStatement;如果为false则直接通过com.mysql.jdbc.PreparedStatement.getInstance来创建
    • useServerPreparedStmts为true时,创建的是ServerPreparedStatement(创建的时候会触发prepare操作,往mysql服务端发送COM_PREPARE指令),本地通过serverSideStatementCache类来缓存ServerPreparedStatement,key为sql

    doc

    相关文章

      网友评论

          本文标题:聊聊mysql jdbc的prepareStatement

          本文链接:https://www.haomeiwen.com/subject/iiufvdtx.html