MyBatis integrates Druid to realize database thread pool management (two)

MyBatis integrates Druid to realize database thread pool management (two)

What is MyBatis

MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures, and advanced mapping. MyBatis avoids almost all JDBC code and manual setting of parameters and obtaining result sets. MyBatis can use simple XML or annotations to configure and map native types, interfaces, and Java POJOs (Plain Old Java Objects) as records in the database.

Main components of MyBatis

  • configuration
  • sqlsession
  • executor

sqlsession parses the configuration configuration (annotated SQL or xml configuration file), uses the corresponding executor to perform database operations, and then processes the executed result set and returns it to the application layer for display processing

For more details, please refer to the above article

MyBatis in-depth understanding and use-MyBatis cache system

MyBatis in-depth understanding and use-TypeHandler

MyBatis in-depth understanding and use-MyBatis

What is Druid?

Druid is the best database connection pool in the Java language. Druid can provide powerful monitoring and extended functions.

For more details, please refer to the above article:

For other related knowledge, please refer to the previous article MyBatis integrates Druid to achieve database thread pool management (1)

Automated assembly process

spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

DataSourceAutoConfiguration automatic assembly realization

@Configuration
@ConditionalOnClass({
    
     DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({
    
     DataSourcePoolMetadataProvidersConfiguration.class,
      DataSourceInitializationConfiguration.class })// 初始化DataSource信息
public class DataSourceAutoConfiguration {
    
    
    @Configuration
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({
    
     DataSource.class, XADataSource.class })
	@Import({
    
     DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
			DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {
    
    

	}
}

Since Druid is used, a new configuration is added, and the configuration source can be found in the previous article

/**
 * @ClassName: DataSource
 * @Description: DataSource 数据源配置类,可选择 DruidDataSource、UnpooledDataSource、PooledDataSource
 * @Author: 尚先生
 * @CreateDate: 2019/5/22 12:44
 * @Version: 1.0
 */
@Configuration
public class DataSourceConfiguration {
    
    
    @Value("${spring.druid.filters}")
    private String filters;
    // 采用 Druid 实现线程池
    @Bean
    @ConfigurationProperties(prefix = "spring.druid")
    public DataSource dataSource() throws SQLException {
    
    
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setFilters(filters);
        return druidDataSource;
    }
}

DruidDataSource code analysis

public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {
    
    
    public DruidDataSource(boolean fairLock){
    
    
        // 默认采用非公平锁机制
        super(fairLock);
        // 配置数据源属性信息
        configFromPropety(System.getProperties());
    }
}

TransactionAutoConfiguration automatic assembly realization

@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({
    
     JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
      // 数据库事务的实现
      DataSourceTransactionManagerAutoConfiguration.class,
      Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
    
    

    
}

Start query processing

AbstractPlatformTransactionManager#getTransaction
DataSourceTransactionManager#doGetTransaction
DataSourceTransactionManager#doBegin
DruidDataSource#getConnection
DruidDataSource#init

Get the connection within the specified time, if timeout new DruidPooledConnection(holder)

private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException {
    
    
    try {
    
    
        lock.lockInterruptibly();
    } catch (InterruptedException e) {
    
    
        connectErrorCount.incrementAndGet();
        throw new SQLException("interrupt", e);
    }
    try {
    
    
        if (maxWait > 0) {
    
    
            holder = pollLast(nanos);
        } else {
    
    
            holder = takeLast();
        }

    } catch (InterruptedException e) {
    
    
        connectErrorCount.incrementAndGet();
        throw new SQLException(e.getMessage(), e);
    } catch (SQLException e) {
    
    
        connectErrorCount.incrementAndGet();
        throw e;
    } finally {
    
    
        lock.unlock();
    }

    holder.incrementUseCount();

    DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder);
    return poolalbeConnection;   
}

Initialize DruidDataSource

public void init() throws SQLException {
    
    
        if (inited) {
    
    
            return;
        }
    	// Lock 实现锁机制
        final ReentrantLock lock = this.lock;
        try {
    
    
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
    
    
            throw new SQLException("interrupt", e);
        }
    	// 保证值初始化一次
        boolean init = false;
        try {
    
    
            if (inited) {
    
    
                return;
            }
           // 设置 reset 开关
            dataSourceStat.setResetStatEnable(this.resetStatEnable);

            // DruidDataSource保存DruidConnectionHolder的数组,保存所有的数据库连接
            // DruidConnectionHolder持有数据库连接,还有所在的DataSource等
            // DruidPooledConnection持有DruidConnectionHolder,所在线程等
            connections = new DruidConnectionHolder[maxActive];
            evictConnections = new DruidConnectionHolder[maxActive];
            keepAliveConnections = new DruidConnectionHolder[maxActive];

            SQLException connectError = null;

            boolean asyncInit = this.asyncInit && createScheduler == null;
            if (!asyncInit) {
    
    
                try {
    
    
                    // 初始化 connection
                    for (int i = 0, size = getInitialSize(); i < size; ++i) {
    
    
                        PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
                        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
                        connections[poolingCount] = holder;
                        incrementPoolingCount();
                    }
            createAndLogThread();
            createAndStartCreatorThread();
            createAndStartDestroyThread();

            initedLatch.await();
            init = true;
            if (keepAlive) {
    
    
                // 异步进行最小任务数处理
                if (createScheduler != null) {
    
    
                    for (int i = 0; i < minIdle; ++i) {
    
    
                        createTaskCount++;
                        CreateConnectionTask task = new CreateConnectionTask();
                        this.createSchedulerFuture = createScheduler.submit(task);
                    }
                } else {
    
    
                    this.emptySignal();
                }
            }
        finally {
    
    
            // 标记初始化完成
            inited = true;
            // 释放锁
            lock.unlock();
        }
    }

Connection acquisition after timeout

// 使用Lock-Condition
DruidConnectionHolder takeLast() throws InterruptedException, SQLException {
    
    
        try {
    
    
            while (poolingCount == 0) {
    
    
                emptySignal(); // 发出信号去创建连接
                notEmptyWaitThreadCount++;
                if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) {
    
    
                    notEmptyWaitThreadPeak = notEmptyWaitThreadCount;
                }
                try {
    
    
                    notEmpty.await(); //发出信号去复用或者创建连接
                } finally {
    
    
                    notEmptyWaitThreadCount--;
                }
                notEmptyWaitCount++;

                if (!enable) {
    
    
                    connectErrorCount.incrementAndGet();
                    throw new DataSourceDisableException();
                }
            }
        } catch (InterruptedException ie) {
    
    
            notEmpty.signal(); // 传播 non-interrupted 线程
            notEmptySignalCount++;
            throw ie;
        }

        decrementPoolingCount();
        DruidConnectionHolder last = connections[poolingCount];
        connections[poolingCount] = null;

        return last;
    }

DruidPooledConnection#close

public void close() throws SQLException {
    
    
    // 如果为 true 表示已经关闭    
    if (this.disable) {
    
    
            return;
        }
        if (filters.size() > 0) {
    
    
            FilterChainImpl filterChain = new FilterChainImpl(dataSource);
            filterChain.dataSource_recycle(this);
        } else {
    
    
            // 回收连接处理
            recycle();
        }
        this.disable = true;
    }

1. DruidDataSource holds an array of DruidConnectionHolder, saves all database connections

private volatile DruidConnectionHolder[] connections;  // 注意这里的volatile

2. DruidConnectionHolder holds the database connection, and the DataSource where it is located, etc.

private final DruidAbstractDataSource dataSource;
private final Connection  conn;
// 成员变量,可以做缓存,也可以做统计
private PreparedStatementPool statementPool;
private final List<Statement> statementTrace = new ArrayList<Statement>(2);

3. DruidPooledConnection holds DruidConnectionHolder, the thread where it is located, etc.

protected volatile DruidConnectionHolder holder;
private final Thread ownerThread;

to sum up

This sharing mainly includes the assembly and source code analysis of the transaction management PlatformTransactionManager and DruidDataSource, the reasonable use of sqlsession connections within the scope of transaction control, the DruidDataSource is used to save the DruidConnectionHolder in the form of an array, and the DruidConnectionHolder is used to save the database connection held and the data source DataSource related Information, use DruidPooledConnection to save current thread information and DruidConnectionHolder array, etc., through the above combination relationship, the problem of dynamic control of the number of connections and sqlSession sharing can be achieved, and the functions of druid's timely, statistical, and dynamic monitoring of the connection of the operation and maintenance layer can be realized.

More excellent articles

Elementary school students in java
https://blog.csdn.net/shang_xs

More MyBatis related

MyBatis in-depth understanding and use-MyBatis cache system
https://blog.csdn.net/shang_xs/article/details/86656353
MyBatis in-depth understanding and use-MyBatis cache system
https://blog.csdn.net/shang_xs/article/details /86656353
MyBatis in-depth understanding and use-TypeHandler
https://blog.csdn.net/shang_xs/article/details/86656173

Spring combines Tomcat and Jndi to realize data source external configuration

https://blog.csdn.net/shang_xs/article/details/90599810
Spring combines Jboss and Jndi to implement data source external configuration
https://blog.csdn.net/shang_xs/article/details/90610242

In-depth study and understanding of Servlet (1)
https://blog.csdn.net/shang_xs/article/details/90371068 In-
depth study and understanding of Servlet (2)
https://blog.csdn.net/shang_xs/article/details/90376489

Please see GitHub for the complete code and related dependencies

https://github.com/dwyanewede/spring-boot/tree/master/spring-webmvc/src/main

Official account recommendation

Insert picture description here

Guess you like

Origin blog.csdn.net/shang_xs/article/details/90751859