1.了解recycle方法,要知道连接池connections,假设连接池已经初始化,连接从connections获取的;事务有两种访问模式read only和read write;read only模式不允许写入修改数据和执行ddl语句,同时可以使存储引擎能够进行性能改进

mysql的原文

set transaction read only
> OK
> 时间: 0s


update t_user set user_id = 1 where user_id = 10
> 1792 - Cannot execute statement in a READ ONLY transaction.
> 时间: 0.003s
set transaction read only
> OK
> 时间: 0s


insert into t_user() values (10)
> 1792 - Cannot execute statement in a READ ONLY transaction.
> 时间: 0s
set transaction read only
> OK
> 时间: 0s


delete from t_user where user_id =10
> 1792 - Cannot execute statement in a READ ONLY transaction.
> 时间: 0.001s

 

Transaction Access Mode
To set the transaction access mode, use a READ WRITE or READ ONLY clause. It is not permitted to specify multiple access-mode clauses in the same SET TRANSACTION statement.

By default, a transaction takes place in read/write mode, with both reads and writes permitted to tables used in the transaction. This mode may be specified explicitly using SET TRANSACTION with an access mode of READ WRITE.

If the transaction access mode is set to READ ONLY, changes to tables are prohibited. This may enable storage engines to make performance improvements that are possible when writes are not permitted.

In read-only mode, it remains possible to change tables created with the TEMPORARY keyword using DML statements. Changes made with DDL statements are not permitted, just as with permanent tables.

The READ WRITE and READ ONLY access modes also may be specified for an individual transaction using the START TRANSACTION statement.
com.mysql.cj.jdbc.ConnectionImpl设置事务只读,执行的sql是set transaction read only;
@Override
    public void setReadOnly(boolean readOnlyFlag) throws SQLException {

        setReadOnlyInternal(readOnlyFlag);
    }

    @Override
    public void setReadOnlyInternal(boolean readOnlyFlag) throws SQLException {
        synchronized (getConnectionMutex()) {
            // note this this is safe even inside a transaction
            if (this.readOnlyPropagatesToServer.getValue() && versionMeetsMinimum(5, 6, 5)) {
                if (!this.useLocalSessionState.getValue() || (readOnlyFlag != this.readOnly)) {
                    this.session.execSQL(null, "set session transaction " + (readOnlyFlag ? "read only" : "read write"), -1, null, false,
                            this.nullStatementResultSetFactory, null, false);
                }
            }

            this.readOnly = readOnlyFlag;
        }
    }

 

DruidPooledConnection.getConnectionInternal,Druid获取连接是拿的池子里的最后一个连接,取出来后,connections的数量会减一,此为借
try {
                if (maxWaitThreadCount > 0
                        && notEmptyWaitThreadCount >= maxWaitThreadCount) {
                    connectErrorCountUpdater.incrementAndGet(this);
                    throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count "
                            + lock.getQueueLength());
                }

                if (onFatalError
                        && onFatalErrorMaxActive > 0
                        && activeCount >= onFatalErrorMaxActive) {
                    connectErrorCountUpdater.incrementAndGet(this);

                    StringBuilder errorMsg = new StringBuilder();
                    errorMsg.append("onFatalError, activeCount ")
                            .append(activeCount)
                            .append(", onFatalErrorMaxActive ")
                            .append(onFatalErrorMaxActive);

                    if (lastFatalErrorTimeMillis > 0) {
                        errorMsg.append(", time '")
                                .append(StringUtils.formatDateTime19(
                                        lastFatalErrorTimeMillis, TimeZone.getDefault()))
                                .append("'");
                    }

                    if (lastFatalErrorSql != null) {
                        errorMsg.append(", sql \n")
                                .append(lastFatalErrorSql);
                    }

                    throw new SQLException(
                            errorMsg.toString(), lastFatalError);
                }

                connectCount++;

                if (createScheduler != null
                        && poolingCount == 0
                        && activeCount < maxActive
                        && creatingCountUpdater.get(this) == 0
                        && createScheduler instanceof ScheduledThreadPoolExecutor) {
                    ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) createScheduler;
                    if (executor.getQueue().size() > 0) {
                        createDirect = true;
                        continue;
                    }
                }

                if (maxWait > 0) {
                    holder = pollLast(nanos);
                } else {
                    holder = takeLast();
                }

                if (holder != null) {
                    if (holder.discard) {
                        continue;
                    }

                    activeCount++;
                    holder.active = true;
                    if (activeCount > activePeak) {
                        activePeak = activeCount;
                        activePeakTime = System.currentTimeMillis();
                    }
                }
            } catch (InterruptedException e) {
                connectErrorCountUpdater.incrementAndGet(this);
                throw new SQLException(e.getMessage(), e);
            } catch (SQLException e) {
                connectErrorCountUpdater.incrementAndGet(this);
                throw e;
            } finally {
                lock.unlock();
            }

            break;
        }

2.回收连接DruidDataSource.recycle

1)判断是否自动提交事务和是否事务只读,如果否的话,回滚事务;只读模式不能做增删改,所以不需要回滚事务

2)如果跟数据库建立的已经关闭,设置holder.active = false

3)把连接放到connections的末尾,连接池数量加一,此为还

boolean putLast(DruidConnectionHolder e, long lastActiveTimeMillis) {
        if (poolingCount >= maxActive || e.discard || this.closed) {
            return false;
        }

        e.lastActiveTimeMillis = lastActiveTimeMillis;
        connections[poolingCount] = e;
        incrementPoolingCount();

        if (poolingCount > poolingPeak) {
            poolingPeak = poolingCount;
            poolingPeakTime = lastActiveTimeMillis;
        }

        notEmpty.signal();
        notEmptySignalCount++;

        return true;
    }

当下想想,按这种,从数组借和还,确实连接池使用数组,时间复杂度最低O(1)

posted on 2022-05-17 23:21  柳无情  阅读(554)  评论(0编辑  收藏  举报