Mysql JDBC调用流程

文章详细解释了Java中使用DriverManager.getConnection与mysqljdbc库建立数据库连接的过程,包括Class.forName加载驱动、真正的连接入口(connect方法)、PreparedStatement的创建和执行等关键步骤。
摘要由CSDN通过智能技术生成

getConnection

java语句如下:

cn = DriverManager.getConnection(
                    "jdbc:mysql://100.83.94.89:3306/mysql?user=root&password=mysql&useEncryption=true");

mysql jdbc代码里没有DriverManager类,这个可能是java自己的类。也没有getConnection的实现(其实有getConnection的实现,但是都不是DriverManager类的,不是上面代码里用到的getConnection)。

getConnection会调用具体某个jdbc驱动的connect方法,在这里就是mysql jdbc驱动的connect方法。所以java代码在DriverManager.getConnection的前面会有一句load jdbc的语句。

Class.forName("com.mysql.cj.jdbc.Driver").newInstance();

mysql jdbc被调用的真正入口是connect方法,详见这篇文章(DriverManager.getConnection()方法涉及到的源码详解-CSDN博客

mysql jdbc的connect代码可能是在这里:

public java.sql.Connection connect(String url, Properties info) throws SQLException {

        try {
            if (!ConnectionUrl.acceptsUrl(url)) {
                /*
                 * According to JDBC spec:
                 * The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the
                 * JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.
                 */
                return null;
            }

            ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);
            switch (conStr.getType()) {
                case SINGLE_CONNECTION:
                    return com.mysql.cj.jdbc.ConnectionImpl.getInstance(conStr.getMainHost());

                case FAILOVER_CONNECTION:
                case FAILOVER_DNS_SRV_CONNECTION:
                    return FailoverConnectionProxy.createProxyInstance(conStr);

                case LOADBALANCE_CONNECTION:
                case LOADBALANCE_DNS_SRV_CONNECTION:
                    return LoadBalancedConnectionProxy.createProxyInstance(conStr);

                case REPLICATION_CONNECTION:
                case REPLICATION_DNS_SRV_CONNECTION:
                    return ReplicationConnectionProxy.createProxyInstance(conStr);

                default:
                    return null;
            }

        } catch (UnsupportedConnectionStringException e) {
            // when Connector/J can't handle this connection string the Driver must return null
            return null;

        } catch (CJException ex) {
            throw ExceptionFactory.createException(UnableToConnectException.class,
                    Messages.getString("NonRegisteringDriver.17", new Object[] { ex.toString() }), ex);
        }
    }

所以,最终return的是个ConnectionImpl对象。

对象在构造函数里,设置一大堆属性之后创建了个真正的网络连接:

createNewIO(false);

unSafeQueryInterceptors();

AbandonedConnectionCleanupThread.trackConnection(this, this.getSession().getNetworkResources());

prepareStatement

prepareStatement也是ConnectionImpl的方法,不过实现很多,在ConnectionWrapper里也有实现。如果server ps打开的话返回的是ServerPreparedStatement,如果client ps的话返回clientPrepareStatement

对象。

public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        synchronized (getConnectionMutex()) {
            checkClosed();

            //
            // FIXME: Create warnings if can't create results of the given type or concurrency
            //
            ClientPreparedStatement pStmt = null;

            boolean canServerPrepare = true;

            String nativeSql = this.processEscapeCodesForPrepStmts.getValue() ? nativeSQL(sql) : sql;

            if (this.useServerPrepStmts.getValue() && this.emulateUnsupportedPstmts.getValue()) {
                canServerPrepare = canHandleAsServerPreparedStatement(nativeSql);
            }

            if (this.useServerPrepStmts.getValue() && canServerPrepare) {
                if (this.cachePrepStmts.getValue()) {
                    synchronized (this.serverSideStatementCache) {
                        pStmt = this.serverSideStatementCache.remove(new CompoundCacheKey(this.database, sql));

                        if (pStmt != null) {
                            ((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).setClosed(false);
                            pStmt.clearParameters();
                        }

                        if (pStmt == null) {
                            try {
                                pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType,
                                        resultSetConcurrency);
                                if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) {
                                    ((com.mysql.cj.jdbc.ServerPreparedStatement) pStmt).isCacheable = true;
                                }

                                pStmt.setResultSetType(resultSetType);
                                pStmt.setResultSetConcurrency(resultSetConcurrency);
                            } catch (SQLException sqlEx) {
                                // Punt, if necessary
                                if (this.emulateUnsupportedPstmts.getValue()) {
                                    pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);

                                    if (sql.length() < this.prepStmtCacheSqlLimit.getValue()) {
                                        this.serverSideStatementCheckCache.put(sql, Boolean.FALSE);
                                    }
                                } else {
                                    throw sqlEx;
                                }
                            }
                        }
                    }
                } else {
                    try {
                        pStmt = ServerPreparedStatement.getInstance(getMultiHostSafeProxy(), nativeSql, this.database, resultSetType, resultSetConcurrency);

                        pStmt.setResultSetType(resultSetType);
                        pStmt.setResultSetConcurrency(resultSetConcurrency);
                    } catch (SQLException sqlEx) {
                        // Punt, if necessary
                        if (this.emulateUnsupportedPstmts.getValue()) {
                            pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
                        } else {
                            throw sqlEx;
                        }
                    }
                }
            } else {
                pStmt = (ClientPreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
            }

            return pStmt;
        }
    }

ServerPreparedStatement对象的构造函数第一个参数事实上就是Connection对象,内部会调用serverPrepare接口执行prepare流程:

protected ServerPreparedStatement(JdbcConnection conn, String sql, String db, int resultSetType, int resultSetConcurrency) throws SQLException {
        super(conn, db);

        checkNullOrEmptyQuery(sql);
        String statementComment = this.session.getProtocol().getQueryComment();
        PreparedQuery prepQuery = (PreparedQuery) this.query;
        prepQuery.setOriginalSql(statementComment == null ? sql : "/* " + statementComment + " */ " + sql);
        prepQuery.setQueryInfo(new QueryInfo(prepQuery.getOriginalSql(), this.session, this.charEncoding));

        this.hasOnDuplicateKeyUpdate = prepQuery.getQueryInfo().containsOnDuplicateKeyUpdate();

        try {
            serverPrepare(sql);
        } catch (CJException | SQLException sqlEx) {
            realClose(false, true);

            throw SQLExceptionsMapping.translateException(sqlEx, this.exceptionInterceptor);
        }

        setResultSetType(resultSetType);
        setResultSetConcurrency(resultSetConcurrency);
    }

ServerPreparedStatement.serverPrepare又会调用ServerPreparedQuery.serverPrepare,真正的核心流程在

ServerPreparedQuery.serverPrepare里。

executeUpdate

最后应该是调用到了StatementImplement.executeUpdateInternal,真正执行的地方是:

rs = ((NativeSession) locallyScopedConn.getSession()).execSQL(this, sql, -1, null, false, getResultSetFactory(), null, isBatch);

执行之后把rs指针存进了自己的属性里:

this.results = rs;

rs.setFirstCharOfQuery(firstStatementChar);

this.updateCount = rs.getUpdateCount();

this.lastInsertId = rs.getUpdateID();

return this.updateCount;

setXXX

最后调用的在NativeQueryBindValue.setBinding方法,只是把数据存了下来。

public void setBinding(Object obj, MysqlType type, int numberOfExecutions, AtomicBoolean sendTypesToServer) {
        if (sendTypesToServer != null) {
            sendTypesToServer.compareAndSet(false, resetToType(type)); // specific to ServerPreparedQuery
        }

        this.value = obj;
        this.targetType = type;
        this.boundBeforeExecutionNum = numberOfExecutions;

        this.isNull = this.targetType == MysqlType.NULL;
        this.isSet = true;
        this.escapeBytesIfNeeded = true;

        Supplier<ValueEncoder> vc = this.protocol.getValueEncoderSupplier(this.isNull ? null : this.value);
        if (vc != null) {
            this.valueEncoder = vc.get();
            this.valueEncoder.init(this.pset, this.serverSession, this.exceptionInterceptor);
        } else {
            throw ExceptionFactory.createException(WrongArgumentException.class,
                    Messages.getString("PreparedStatement.67", new Object[] { obj.getClass().getName(), type.name() }), this.exceptionInterceptor);
        }
    }

executeQuery

和executeUpdate类似,调用到了executeInternal里,最后调用的是execSQL获取rs。

protected <M extends Message> ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, M sendPacket, boolean createStreamingResultSet,
            boolean queryIsSelectOnly, ColumnDefinition metadata, boolean isBatch) throws SQLException {
        synchronized (checkClosed().getConnectionMutex()) {
            try {

                JdbcConnection locallyScopedConnection = this.connection;

                ((PreparedQuery) this.query).getQueryBindings()
                        .setNumberOfExecutions(((PreparedQuery) this.query).getQueryBindings().getNumberOfExecutions() + 1);

                ResultSetInternalMethods rs;

                CancelQueryTask timeoutTask = null;

                try {
                    timeoutTask = startQueryTimer(this, getTimeoutInMillis());

                    if (!isBatch) {
                        statementBegins();
                    }

                    rs = ((NativeSession) locallyScopedConnection.getSession()).execSQL(this, null, maxRowsToRetrieve, (NativePacketPayload) sendPacket,
                            createStreamingResultSet, getResultSetFactory(), metadata, isBatch);

                    if (timeoutTask != null) {
                        stopQueryTimer(timeoutTask, true, true);
                        timeoutTask = null;
                    }

                } finally {
                    if (!isBatch) {
                        this.query.getStatementExecuting().set(false);
                    }

                    stopQueryTimer(timeoutTask, false, false);
                }

                return rs;
            } catch (NullPointerException npe) {
                checkClosed(); // we can't synchronize ourselves against async connection-close due to deadlock issues, so this is the next best thing for
                              // this particular corner case.

                throw npe;
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值