Mysql预编译SQL

JDBC驱动初始化-Mysql: http://donald-draper.iteye.com/blog/2342010
JDBC连接的获取: http://donald-draper.iteye.com/blog/2342011
Mysql负载均衡连接的获取: http://donald-draper.iteye.com/blog/2342089
Mysql主从复制读写分离连接的获取: http://donald-draper.iteye.com/blog/2342108
ConnectionImp创建MysqlIO : http://donald-draper.iteye.com/blog/2342959
Mysql预编译SQL: http://donald-draper.iteye.com/blog/2342960
MysqlSQL PreparedStatement的查询: http://donald-draper.iteye.com/blog/2343083
MySQL ServerPreparedStatement查询: http://donald-draper.iteye.com/blog/2343124
前几篇文章中,我们谈到连接的获取,mysqlIO的初始化,今天来看一下SQL的预编译,从下面这一句开始:
PreparedStatement ps = con.prepareStatement("select count(*) from ?");

//ConnectionImpl
//获取sql的PreparedStatement
 public PreparedStatement prepareStatement(String sql)
        throws SQLException
    {
        //委托给prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
        return prepareStatement(sql, 1003, 1007);
    }
//预编译PreparedStatement
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
        throws SQLException
    {
        //检查连接是否关闭,关闭则返回
        checkClosed();
        com.mysql.jdbc.PreparedStatement pStmt = null;
        boolean canServerPrepare = true;//server是否可以预编译sql
        String nativeSql = getProcessEscapeCodesForPrepStmts() ? nativeSQL(sql) : sql;
	//判断server是否可以预编译sql
        if(useServerPreparedStmts && getEmulateUnsupportedPstmts())
            canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
	//server可以预编译sql,且PreparedStatement为ServerPreparedStatement
        if(useServerPreparedStmts && canServerPrepare)
        {
	    //如果Server需要缓存PreparedStatement
            if(getCachePreparedStatements())
	        //锁定server缓存, private LRUCache serverSideStatementCache;
                synchronized(serverSideStatementCache)
                {   
		    //从缓存中移除sql对应的ServerPreparedStatement
                    pStmt = (ServerPreparedStatement)serverSideStatementCache.remove(sql);
                    if(pStmt != null)
                    {
                        ((ServerPreparedStatement)pStmt).setClosed(false);
                        pStmt.clearParameters();
                    }
                    if(pStmt == null)
                        try
                        {
			    //如果缓存中不存在sql对应的ServerPreparedStatement,则创建
                            pStmt = ServerPreparedStatement.getInstance(this, nativeSql, database, resultSetType, resultSetConcurrency);
                            if(sql.length() < getPreparedStatementCacheSqlLimit())
                                ((ServerPreparedStatement)pStmt).isCached = true;
		            //设置结果集类型
                            pStmt.setResultSetType(resultSetType);
			    //设置结果集并发策略
                            pStmt.setResultSetConcurrency(resultSetConcurrency);
                        }
                        catch(SQLException sqlEx)
                        {
                            if(getEmulateUnsupportedPstmts())
                            {
                                pStmt = (com.mysql.jdbc.PreparedStatement)clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
                                if(sql.length() < getPreparedStatementCacheSqlLimit())
                                    serverSideStatementCheckCache.put(sql, Boolean.FALSE);
                            } else
                            {
                                throw sqlEx;
                            }
                        }
                }
            else
                try
                {   //如果Server不缓存PreparedStatement,则直接创建对应的ServerPreparedStatement
                    pStmt = ServerPreparedStatement.getInstance(this, nativeSql, database, resultSetType, resultSetConcurrency);
                    pStmt.setResultSetType(resultSetType);
                    pStmt.setResultSetConcurrency(resultSetConcurrency);
                }
                catch(SQLException sqlEx)
                {
                    if(getEmulateUnsupportedPstmts())
                        pStmt = (com.mysql.jdbc.PreparedStatement)clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
                    else
                        throw sqlEx;
                }
        } else
        {
	   //如果server不可以预编译sql,则创建sql对应的为clientPrepareStatement
            pStmt = (com.mysql.jdbc.PreparedStatement)clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
        }
        return pStmt;
    }

从上可以看出prepareStatement方法首先,检查连接是否关闭,关闭则直接返回;
根据server是否可以预编译sql和PreparedStatement是否为ServerPreparedStatement信息,
来确定返回的prepareStatement是ServerPreparedStatement还是com.mysql.jdbc.PreparedStatement,server可以预编译sql,且PreparedStatement为ServerPreparedStatement则返回的是ServerPreparedStatement,否则返回的是com.mysql.jdbc.PreparedStatement。
这里有两点要看,先看第一点ServerPreparedStatement,再看第二点clientPrepareStatement
1.
//如果缓存中不存在sql对应的ServerPreparedStatement,则创建
pStmt = ServerPreparedStatement.getInstance(this, nativeSql, database, resultSetType, resultSetConcurrency);

2.
//如果server不可以预编译sql,则创建sql对应的为clientPrepareStatement
pStmt = (com.mysql.jdbc.PreparedStatement)clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);




//如果缓存中不存在sql对应的ServerPreparedStatement,则创建
pStmt = ServerPreparedStatement.getInstance(this, nativeSql, database, resultSetType, resultSetConcurrency);

public class ServerPreparedStatement extends com.mysql.jdbc.PreparedStatement
{
    //JDBC4ServerPreparedStatement构造函数
    private static final Constructor JDBC_4_SPS_CTOR;
    protected static final int BLOB_STREAM_READ_BUF_SIZE = 8192;
    private static final byte MAX_DATE_REP_LENGTH = 5;
    private static final byte MAX_DATETIME_REP_LENGTH = 12;
    private static final byte MAX_TIME_REP_LENGTH = 13;
    private boolean hasOnDuplicateKeyUpdate;
    private boolean detectedLongParameterSwitch;
    private int fieldCount;
    private boolean invalid;
    private SQLException invalidationException;
    private boolean isSelectQuery;//是否是select查询
    private Buffer outByteBuffer;
    private BindValue parameterBindings[];
    private Field parameterFields[];//参数域
    private Field resultFields[];//结果域
    private boolean sendTypesToServer;
    private long serverStatementId;
    private int stringTypeCode;
    private boolean serverNeedsResetBeforeEachExecution;
    protected boolean isCached;
    private boolean useAutoSlowLog;
    private Calendar serverTzCalendar;
    private Calendar defaultTzCalendar;
    private boolean hasCheckedRewrite;
    private boolean canRewrite;
    private int locationOfOnDuplicateKeyUpdate;

    static 
    {
        if(Util.isJdbc4())
            try
            {
                JDBC_4_SPS_CTOR = Class.forName("com.mysql.jdbc.JDBC4ServerPreparedStatement").getConstructor(new Class[] {
                    com.mysql.jdbc.ConnectionImpl.class, java.lang.String.class, java.lang.String.class, Integer.TYPE, Integer.TYPE
                });
            }
            catch(SecurityException e)
            {
                throw new RuntimeException(e);
            }
            catch(NoSuchMethodException e)
            {
                throw new RuntimeException(e);
            }
            catch(ClassNotFoundException e)
            {
                throw new RuntimeException(e);
            }
        else
            JDBC_4_SPS_CTOR = null;
    }
    //获取ServerPreparedStatement实例
     protected static ServerPreparedStatement getInstance(ConnectionImpl conn, String sql, String catalog, int resultSetType, int resultSetConcurrency)
        throws SQLException
    {
        if(!Util.isJdbc4())
            return new ServerPreparedStatement(conn, sql, catalog, resultSetType, resultSetConcurrency);
        return (ServerPreparedStatement)JDBC_4_SPS_CTOR.newInstance(new Object[] {
            conn, sql, catalog, Constants.integerValueOf(resultSetType), Constants.integerValueOf(resultSetConcurrency)
        });
        IllegalArgumentException e;
        e;
        throw new SQLException(e.toString(), "S1000");
        e;
        throw new SQLException(e.toString(), "S1000");
        e;
        throw new SQLException(e.toString(), "S1000");
        e;
        Throwable target = e.getTargetException();
        if(target instanceof SQLException)
            throw (SQLException)target;
        else
            throw new SQLException(target.toString(), "S1000");
    }
    //ServerPreparedStatement构造函数
    protected ServerPreparedStatement(ConnectionImpl conn, String sql, String catalog, int resultSetType, int resultSetConcurrency)
        throws SQLException
    {
        super(conn, catalog);
        hasOnDuplicateKeyUpdate = false;
        detectedLongParameterSwitch = false;
        invalid = false;
        sendTypesToServer = false;
        stringTypeCode = 254;
        isCached = false;
        hasCheckedRewrite = false;
        canRewrite = false;
        locationOfOnDuplicateKeyUpdate = -2;
        checkNullOrEmptyQuery(sql);
        hasOnDuplicateKeyUpdate = containsOnDuplicateKeyInString(sql);
        int startOfStatement = findStartOfStatement(sql);
        firstCharOfStmt = StringUtils.firstAlphaCharUc(sql, startOfStatement);
        isSelectQuery = 'S' == firstCharOfStmt;
        if(connection.versionMeetsMinimum(5, 0, 0))
            serverNeedsResetBeforeEachExecution = !connection.versionMeetsMinimum(5, 0, 3);
        else
            serverNeedsResetBeforeEachExecution = !connection.versionMeetsMinimum(4, 1, 10);
        useAutoSlowLog = connection.getAutoSlowLog();
        useTrueBoolean = connection.versionMeetsMinimum(3, 21, 23);
        hasLimitClause = StringUtils.indexOfIgnoreCase(sql, "LIMIT") != -1;
        String statementComment = connection.getStatementComment();
        originalSql = statementComment != null ? "/* " + statementComment + " */ " + sql : sql;
        if(connection.versionMeetsMinimum(4, 1, 2))
            stringTypeCode = 253;
        else
            stringTypeCode = 254;
        try
        {
	    //关键这里,预编译sql
            serverPrepare(sql);
        }
        catch(SQLException sqlEx)
        {
            realClose(false, true);
            throw sqlEx;
        }
        catch(Exception ex)
        {
            realClose(false, true);
            SQLException sqlEx = SQLError.createSQLException(ex.toString(), "S1000", getExceptionInterceptor());
            sqlEx.initCause(ex);
            throw sqlEx;
        }
        setResultSetType(resultSetType);
        setResultSetConcurrency(resultSetConcurrency);
        parameterTypes = new int[parameterCount];
    }
}

//预编译sql
 private void serverPrepare(String sql)
        throws SQLException
    {
        //获取connection的互斥锁
        Object obj = connection.getMutex();
        JVM INSTR monitorenter ;
        MysqlIO mysql;
	//获取 MysqlIO
        mysql = connection.getIO();
        if(connection.getAutoGenerateTestcaseScript())
            dumpPrepareForTestcase();
        try
        {
            long begin = 0L;
            if(StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA"))
                isLoadDataQuery = true;
            else
                isLoadDataQuery = false;
            if(connection.getProfileSql())
                begin = System.currentTimeMillis();
            String characterEncoding = null;
	    //获取connection编码信息
            String connectionEncoding = connection.getEncoding();
            if(!isLoadDataQuery && connection.getUseUnicode() && connectionEncoding != null)
                characterEncoding = connectionEncoding;
            //MysqlIO发送sql命令
            Buffer prepareResultPacket = mysql.sendCommand(22, sql, null, false, characterEncoding, 0);
            if(connection.versionMeetsMinimum(4, 1, 1))
                prepareResultPacket.setPosition(1);
            else
                prepareResultPacket.setPosition(0);
            serverStatementId = prepareResultPacket.readLong();
            fieldCount = prepareResultPacket.readInt();
            parameterCount = prepareResultPacket.readInt();
            parameterBindings = new BindValue[parameterCount];
            for(int i = 0; i < parameterCount; i++)
                parameterBindings[i] = new BindValue();

            connection.incrementNumberOfPrepares();
            if(profileSQL)
                eventSink.consumeEvent(new ProfilerEvent((byte)2, "", currentCatalog, connectionId, statementId, -1, System.currentTimeMillis(), mysql.getCurrentTimeNanosOrMillis() - begin, mysql.getQueryTimingUnits(), null, new Throwable(), truncateQueryToLog(sql)));
            if(parameterCount > 0 && connection.versionMeetsMinimum(4, 1, 2) && !mysql.isVersion(5, 0, 0))
            {
                parameterFields = new Field[parameterCount];
                Buffer metaDataPacket = mysql.readPacket();
                for(int i = 0; !metaDataPacket.isLastDataPacket() && i < parameterCount; metaDataPacket = mysql.readPacket())
                    parameterFields[i++] = mysql.unpackField(metaDataPacket, false);

            }
            if(fieldCount > 0)
            {
                resultFields = new Field[fieldCount];
                Buffer fieldPacket = mysql.readPacket();
                for(int i = 0; !fieldPacket.isLastDataPacket() && i < fieldCount; fieldPacket = mysql.readPacket())
                    resultFields[i++] = mysql.unpackField(fieldPacket, false);

            }
        }
        catch(SQLException sqlEx)
        {
            if(connection.getDumpQueriesOnException())
            {
                StringBuffer messageBuf = new StringBuffer(originalSql.length() + 32);
                messageBuf.append("\n\nQuery being prepared when exception was thrown:\n\n");
                messageBuf.append(originalSql);
                sqlEx = ConnectionImpl.appendMessageToException(sqlEx, messageBuf.toString(), getExceptionInterceptor());
            }
            throw sqlEx;
        }
        connection.getIO().clearInputStream();
        break MISSING_BLOCK_LABEL_557;
        Exception exception;
        exception;
        connection.getIO().clearInputStream();
        throw exception;
        Exception exception1;
        exception1;
        throw exception1;
    }

来看这一句:
//MysqlIO发送sql命令
Buffer prepareResultPacket = mysql.sendCommand(22, sql, null, false, characterEncoding, 0);

//MysqlIO
 final Buffer sendCommand(int command, String extraData, Buffer queryPacket, boolean skipCheck, String extraDataCharEncoding, int timeoutMillis)
        throws SQLException
    {
        commandCount++;
        enablePacketDebug = connection.getEnablePacketDebug();
        readPacketSequence = 0;
        int oldTimeout = 0;
        if(timeoutMillis != 0)
            try
            {
                oldTimeout = mysqlConnection.getSoTimeout();
                mysqlConnection.setSoTimeout(timeoutMillis);
            }
            catch(SocketException e)
            {
                throw SQLError.createCommunicationsException(connection, lastPacketSentTimeMs, lastPacketReceivedTimeMs, e, getExceptionInterceptor());
            }
        try
        {
            Buffer buffer;
            try
            {
                checkForOutstandingStreamingData();
                oldServerStatus = serverStatus;
                serverStatus = 0;
                hadWarnings = false;
                warningCount = 0;
                queryNoIndexUsed = false;
                queryBadIndexUsed = false;
                serverQueryWasSlow = false;
                if(useCompression)
                {
                    int bytesLeft = mysqlInput.available();
                    if(bytesLeft > 0)
                        mysqlInput.skip(bytesLeft);
                }
                try
                {
                    clearInputStream();
                    if(queryPacket == null)
                    {
                        int packLength = 8 + (extraData == null ? 0 : extraData.length()) + 2;
                        if(sendPacket == null)
                            sendPacket = new Buffer(packLength);
                        packetSequence = -1;
                        readPacketSequence = 0;
                        checkPacketSequence = true;
                        sendPacket.clear();
                        sendPacket.writeByte((byte)command);
                        if(command == 2 || command == 5 || command == 6 || command == 3 || command == 22)
                        {
                            if(extraDataCharEncoding == null)
                                sendPacket.writeStringNoNull(extraData);
                            else
                                sendPacket.writeStringNoNull(extraData, extraDataCharEncoding, connection.getServerCharacterEncoding(), connection.parserKnowsUnicode(), connection);
                        } else
                        if(command == 12)
                        {
                            long id = Long.parseLong(extraData);
                            sendPacket.writeLong(id);
                        }
			//发送sql Packet
                        send(sendPacket, sendPacket.getPosition());
                    } else
                    {
                        packetSequence = -1;
                        send(queryPacket, queryPacket.getPosition());
                    }
                }
                catch(SQLException sqlEx)
                {
                    throw sqlEx;
                }
                catch(Exception ex)
                {
                    throw SQLError.createCommunicationsException(connection, lastPacketSentTimeMs, lastPacketReceivedTimeMs, ex, getExceptionInterceptor());
                }
                Buffer returnPacket = null;
                if(!skipCheck)
                {
                    if(command == 23 || command == 26)
                    {
                        readPacketSequence = 0;
                        packetSequenceReset = true;
                    }
                    returnPacket = checkErrorPacket(command);
                }
                buffer = returnPacket;
            }
            catch(IOException ioEx)
            {
                throw SQLError.createCommunicationsException(connection, lastPacketSentTimeMs, lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
            }
            return buffer;
        }
        finally
        {
            if(timeoutMillis != 0)
                try
                {
                    mysqlConnection.setSoTimeout(oldTimeout);
                }
                catch(SocketException e)
                {
                    throw SQLError.createCommunicationsException(connection, lastPacketSentTimeMs, lastPacketReceivedTimeMs, e, getExceptionInterceptor());
                }
        }
    }
//发送sql Packet
 private final void sendSplitPackets(Buffer packet)
        throws SQLException
    {
        try
        {
            Buffer headerPacket = splitBufRef != null ? (Buffer)splitBufRef.get() : null;
            if(headerPacket == null)
            {
                headerPacket = new Buffer(maxThreeBytes + 4);
                splitBufRef = new SoftReference(headerPacket);
            }
            int len = packet.getPosition();
            int splitSize = maxThreeBytes;
            int originalPacketPos = 4;
            byte origPacketBytes[] = packet.getByteBuffer();
            byte headerPacketBytes[] = headerPacket.getByteBuffer();
            int packetLen;
            for(; len >= maxThreeBytes; len -= splitSize)
            {
                packetSequence++;
                headerPacket.setPosition(0);
                headerPacket.writeLongInt(splitSize);
                headerPacket.writeByte(packetSequence);
                System.arraycopy(origPacketBytes, originalPacketPos, headerPacketBytes, 4, splitSize);
                packetLen = splitSize + 4;
                if(!useCompression)
                {
                    mysqlOutput.write(headerPacketBytes, 0, splitSize + 4);
                    mysqlOutput.flush();
                } else
                {
                    headerPacket.setPosition(0);
                    Buffer packetToSend = compressPacket(headerPacket, 4, splitSize, 4);
                    packetLen = packetToSend.getPosition();
                    mysqlOutput.write(packetToSend.getByteBuffer(), 0, packetLen);
                    mysqlOutput.flush();
                }
                originalPacketPos += splitSize;
            }

            headerPacket.clear();
            headerPacket.setPosition(0);
            headerPacket.writeLongInt(len - 4);
            packetSequence++;
            headerPacket.writeByte(packetSequence);
            if(len != 0)
                System.arraycopy(origPacketBytes, originalPacketPos, headerPacketBytes, 4, len - 4);
            packetLen = len - 4;
            if(!useCompression)
            {
	        //将数据包写入输出流
		 protected BufferedOutputStream mysqlOutput;
                mysqlOutput.write(headerPacket.getByteBuffer(), 0, len);
                mysqlOutput.flush();
            } else
            {
                headerPacket.setPosition(0);
                Buffer packetToSend = compressPacket(headerPacket, 4, packetLen, 4);
                packetLen = packetToSend.getPosition();
                mysqlOutput.write(packetToSend.getByteBuffer(), 0, packetLen);
                mysqlOutput.flush();
            }
        }
        catch(IOException ioEx)
        {
            throw SQLError.createCommunicationsException(connection, lastPacketSentTimeMs, lastPacketReceivedTimeMs, ioEx, getExceptionInterceptor());
        }
    }

从上面可以看出,ServerPreparedStatement实际上就是通过MysqlIO,将sql发送到Server端。
2.
//如果server不可以预编译sql,则创建sql对应的为clientPrepareStatement
pStmt = (com.mysql.jdbc.PreparedStatement)clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);


protected PreparedStatement clientPrepareStatement(String sql, int resultSetType, int resultSetConcurrency, boolean processEscapeCodesIfNeeded)
        throws SQLException
    {
        checkClosed();
        String nativeSql = !processEscapeCodesIfNeeded || !getProcessEscapeCodesForPrepStmts() ? sql : nativeSQL(sql);
        com.mysql.jdbc.PreparedStatement pStmt = null;
        if(getCachePreparedStatements())
            synchronized(cachedPreparedStatementParams)
            {
	        //如果缓存,则从缓存中,获取对应的PreparedStatement.ParseInfo
                PreparedStatement.ParseInfo pStmtInfo = (PreparedStatement.ParseInfo)cachedPreparedStatementParams.get(nativeSql);
                if(pStmtInfo == null)
                {
		    //如果缓存中,不存在ParseInfo,则创建PreparedStatement
                    pStmt = PreparedStatement.getInstance(this, nativeSql, database);
                    PreparedStatement.ParseInfo parseInfo = pStmt.getParseInfo();
                    if(parseInfo.statementLength < getPreparedStatementCacheSqlLimit())
                    {
                        if(cachedPreparedStatementParams.size() >= getPreparedStatementCacheSize())
                        {
                            Iterator oldestIter = cachedPreparedStatementParams.keySet().iterator();
                            long lruTime = 9223372036854775807L;
                            String oldestSql = null;
                            do
                            {
                                if(!oldestIter.hasNext())
                                    break;
                                String sqlKey = (String)oldestIter.next();
                                PreparedStatement.ParseInfo lruInfo = (PreparedStatement.ParseInfo)cachedPreparedStatementParams.get(sqlKey);
                                if(lruInfo.lastUsed < lruTime)
                                {
                                    lruTime = lruInfo.lastUsed;
                                    oldestSql = sqlKey;
                                }
                            } while(true);
                            if(oldestSql != null)
                                cachedPreparedStatementParams.remove(oldestSql);
                        }
                        cachedPreparedStatementParams.put(nativeSql, pStmt.getParseInfo());
                    }
                } else
                {
                    pStmtInfo.lastUsed = System.currentTimeMillis();
                    pStmt = new com.mysql.jdbc.PreparedStatement(this, nativeSql, database, pStmtInfo);
                }
            }
        else
            pStmt = PreparedStatement.getInstance(this, nativeSql, database);
        pStmt.setResultSetType(resultSetType);
        pStmt.setResultSetConcurrency(resultSetConcurrency);
        return pStmt;
    }

总结:
prepareStatement方法首先,检查连接是否关闭,关闭则直接返回;
根据server是否可以预编译sql和PreparedStatement是否为ServerPreparedStatement信息,
来确定返回的prepareStatement是ServerPreparedStatement还是com.mysql.jdbc.PreparedStatement,server可以预编译sql,且PreparedStatement为ServerPreparedStatement则返回的是ServerPreparedStatement
否则返回的是com.mysql.jdbc.PreparedStatement。ServerPreparedStatement实际上就是通过MysqlIO,将sql发送到Server端。


//LRUCache,LRUCache实际上是一个Map
public class LRUCache extends LinkedHashMap
{
    public LRUCache(int maxSize)
    {
        super(maxSize);
        maxElements = maxSize;
    }
    //关键在这个方法,当Map,put或putAll时,当添加元素后,Map的size大于其maxSize,调用
    //此方法,判断是否需要移除Eldest元素
    protected boolean removeEldestEntry(java.util.Map.Entry eldest)
    {
        return size() > maxElements;
    }
    private static final long serialVersionUID = 1L;
    protected int maxElements;
}

 
//MysqlIO
class MysqlIO
{

    private static final int UTF8_CHARSET_INDEX = 33;
    private static final String CODE_PAGE_1252 = "Cp1252";
    protected static final int NULL_LENGTH = -1;
    protected static final int COMP_HEADER_LENGTH = 3;
    protected static final int MIN_COMPRESS_LEN = 50;
    protected static final int HEADER_LENGTH = 4;
    protected static final int AUTH_411_OVERHEAD = 33;
    private static int maxBufferSize = 65535;
    private static final int CLIENT_COMPRESS = 32;
    protected static final int CLIENT_CONNECT_WITH_DB = 8;
    private static final int CLIENT_FOUND_ROWS = 2;
    private static final int CLIENT_LOCAL_FILES = 128;
    private static final int CLIENT_LONG_FLAG = 4;
    private static final int CLIENT_LONG_PASSWORD = 1;
    private static final int CLIENT_PROTOCOL_41 = 512;
    private static final int CLIENT_INTERACTIVE = 1024;
    protected static final int CLIENT_SSL = 2048;
    private static final int CLIENT_TRANSACTIONS = 8192;
    protected static final int CLIENT_RESERVED = 16384;
    protected static final int CLIENT_SECURE_CONNECTION = 32768;
    private static final int CLIENT_MULTI_QUERIES = 65536;
    private static final int CLIENT_MULTI_RESULTS = 131072;
    private static final int SERVER_STATUS_IN_TRANS = 1;
    private static final int SERVER_STATUS_AUTOCOMMIT = 2;
    static final int SERVER_MORE_RESULTS_EXISTS = 8;
    private static final int SERVER_QUERY_NO_GOOD_INDEX_USED = 16;
    private static final int SERVER_QUERY_NO_INDEX_USED = 32;
    private static final int SERVER_QUERY_WAS_SLOW = 2048;
    private static final int SERVER_STATUS_CURSOR_EXISTS = 64;
    private static final String FALSE_SCRAMBLE = "xxxxxxxx";
    protected static final int MAX_QUERY_SIZE_TO_LOG = 1024;
    protected static final int MAX_QUERY_SIZE_TO_EXPLAIN = 1048576;
    protected static final int INITIAL_PACKET_SIZE = 1024;
    private static String jvmPlatformCharset = null;
    protected static final String ZERO_DATE_VALUE_MARKER = "0000-00-00";
    protected static final String ZERO_DATETIME_VALUE_MARKER = "0000-00-00 00:00:00";
    private static final int MAX_PACKET_DUMP_LENGTH = 1024;
    private boolean packetSequenceReset;
    protected int serverCharsetIndex;
    private Buffer reusablePacket;
    private Buffer sendPacket;
    private Buffer sharedSendPacket;
    protected BufferedOutputStream mysqlOutput;
    protected ConnectionImpl connection;//Mysql connection
    private Deflater deflater;
    protected InputStream mysqlInput;//mysql输入流
    private LinkedList packetDebugRingBuffer;
    private RowData streamingData;
    protected Socket mysqlConnection;//mysql socket
    private SocketFactory socketFactory;// mysql socket的工场
    private SoftReference loadFileBufRef;
    private SoftReference splitBufRef;
    protected String host;//host
    protected String seed;
    private String serverVersion;
    private String socketFactoryClassName;
    private byte packetHeaderBuf[];
    private boolean colDecimalNeedsBump;
    private boolean hadWarnings;
    private boolean has41NewNewProt;
    private boolean hasLongColumnInfo;
    private boolean isInteractiveClient;
    private boolean logSlowQueries;
    private boolean platformDbCharsetMatches;
    private boolean profileSql;
    private boolean queryBadIndexUsed;
    private boolean queryNoIndexUsed;
    private boolean serverQueryWasSlow;
    private boolean use41Extensions;
    private boolean useCompression;
    private boolean useNewLargePackets;
    private boolean useNewUpdateCounts;
    private byte packetSequence;
    private byte readPacketSequence;
    private boolean checkPacketSequence;
    private byte protocolVersion;
    private int maxAllowedPacket;
    protected int maxThreeBytes;
    protected int port;
    protected int serverCapabilities;
    private int serverMajorVersion;
    private int serverMinorVersion;
    private int oldServerStatus;
    private int serverStatus;
    private int serverSubMinorVersion;
    private int warningCount;
    protected long clientParam;
    protected long lastPacketSentTimeMs;
    protected long lastPacketReceivedTimeMs;
    private boolean traceProtocol;
    private boolean enablePacketDebug;
    private Calendar sessionCalendar;
    private boolean useConnectWithDb;
    private boolean needToGrabQueryFromPacket;
    private boolean autoGenerateTestcaseScript;
    private long threadId;
    private boolean useNanosForElapsedTime;
    private long slowQueryThreshold;
    private String queryTimingUnits;
    private boolean useDirectRowUnpack;
    private int useBufferRowSizeThreshold;
    private int commandCount;
    private List statementInterceptors;
    private ExceptionInterceptor exceptionInterceptor;
    private int statementExecutionDepth;
    private boolean useAutoSlowLog;

    static 
    {
        OutputStreamWriter outWriter = null;
        try
        {
            outWriter = new OutputStreamWriter(new ByteArrayOutputStream());
            jvmPlatformCharset = outWriter.getEncoding();
        }
        finally
        {
            try
            {
                if(outWriter != null)
                    outWriter.close();
            }
            catch(IOException ioEx) { }
        }
    }
//MysqlIO构造
 public MysqlIO(String host, int port, Properties props, String socketFactoryClassName, ConnectionImpl conn, int socketTimeout, int useBufferRowSizeThreshold)
        throws IOException, SQLException
    {
        packetSequenceReset = false;
        reusablePacket = null;
        sendPacket = null;
        sharedSendPacket = null;
        mysqlOutput = null;
        deflater = null;
        mysqlInput = null;
        packetDebugRingBuffer = null;
        streamingData = null;
        mysqlConnection = null;
        socketFactory = null;
        this.host = null;
        serverVersion = null;
        this.socketFactoryClassName = null;
        packetHeaderBuf = new byte[4];
        colDecimalNeedsBump = false;
        hadWarnings = false;
        has41NewNewProt = false;
        hasLongColumnInfo = false;
        isInteractiveClient = false;
        logSlowQueries = false;
        platformDbCharsetMatches = true;
        profileSql = false;
        queryBadIndexUsed = false;
        queryNoIndexUsed = false;
        serverQueryWasSlow = false;
        use41Extensions = false;
        useCompression = false;
        useNewLargePackets = false;
        useNewUpdateCounts = false;
        packetSequence = 0;
        readPacketSequence = -1;
        checkPacketSequence = false;
        protocolVersion = 0;
        maxAllowedPacket = 1048576;
        maxThreeBytes = 16581375;
        this.port = 3306;
        serverMajorVersion = 0;
        serverMinorVersion = 0;
        oldServerStatus = 0;
        serverStatus = 0;
        serverSubMinorVersion = 0;
        warningCount = 0;
        clientParam = 0L;
        lastPacketSentTimeMs = 0L;
        lastPacketReceivedTimeMs = 0L;
        traceProtocol = false;
        enablePacketDebug = false;
        useDirectRowUnpack = true;
        commandCount = 0;
        statementExecutionDepth = 0;
        connection = conn;
        if(connection.getEnablePacketDebug())
            packetDebugRingBuffer = new LinkedList();
        traceProtocol = connection.getTraceProtocol();
        useAutoSlowLog = connection.getAutoSlowLog();
        this.useBufferRowSizeThreshold = useBufferRowSizeThreshold;
        useDirectRowUnpack = connection.getUseDirectRowUnpack();
        logSlowQueries = connection.getLogSlowQueries();
        reusablePacket = new Buffer(1024);
        sendPacket = new Buffer(1024);
        this.port = port;
        this.host = host;
        this.socketFactoryClassName = socketFactoryClassName;
	//创建socket的工场
        socketFactory = createSocketFactory();
        exceptionInterceptor = connection.getExceptionInterceptor();
        try
        {
	    //从socket的工场获取连接
            mysqlConnection = socketFactory.connect(this.host, this.port, props);
            if(socketTimeout != 0)
                try
                {
                    mysqlConnection.setSoTimeout(socketTimeout);
                }
                catch(Exception ex) { }
	    //握手
            mysqlConnection = socketFactory.beforeHandshake();
            if(connection.getUseReadAheadInput())
                mysqlInput = new ReadAheadInputStream(mysqlConnection.getInputStream(), 16384, connection.getTraceProtocol(), connection.getLog());
            else
            if(connection.useUnbufferedInput())
	        //从mysqlConnection获取输入流
                mysqlInput = mysqlConnection.getInputStream();
            else
                mysqlInput = new BufferedInputStream(mysqlConnection.getInputStream(), 16384);
	    //初始化mysqlOutput输出流
            mysqlOutput = new BufferedOutputStream(mysqlConnection.getOutputStream(), 16384);
            isInteractiveClient = connection.getInteractiveClient();
            profileSql = connection.getProfileSql();
            sessionCalendar = Calendar.getInstance();
            autoGenerateTestcaseScript = connection.getAutoGenerateTestcaseScript();
            needToGrabQueryFromPacket = profileSql || logSlowQueries || autoGenerateTestcaseScript;
            if(connection.getUseNanosForElapsedTime() && Util.nanoTimeAvailable())
            {
                useNanosForElapsedTime = true;
                queryTimingUnits = Messages.getString("Nanoseconds");
            } else
            {
                queryTimingUnits = Messages.getString("Milliseconds");
            }
            if(connection.getLogSlowQueries())
                calculateSlowQueryThreshold();
        }
        catch(IOException ioEx)
        {
            throw SQLError.createCommunicationsException(connection, 0L, 0L, ioEx, getExceptionInterceptor());
        }
    }
}

猜你喜欢

转载自donald-draper.iteye.com/blog/2342960