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

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

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:

Share source code related maven dependencies

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.0</version>
</dependency>

Mybatis and druid partial configuration

spring.application.name=think-in-spring-boot
server.port=8080
# 开启所有endpoint
management.endpoints.web.exposure.include= *

# mybatis相关配置
mybatis.mapper-locations=classpath*:/mapper/*.xml
mybatis.type-aliases-package=think.in.spring.boot.model
mybatis.type-handlers-package=think.in.spring.boot.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30

# 日志级别
debug=true
logging.level.root=info
logging.level.tk.mybatis.springboot.mapper=trace

# DataSource相关配置
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# druid相关配置
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true

Source code analysis

Automated assembly process

Source code entry

spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

Loading process

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports()assemblyorg.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

Assembly conditions

@org.springframework.context.annotation.Configuration
@ConditionalOnClass({
    
     SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
// 最先装配 即:Sqlsession要持有 DataSource 和 Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class) 
public class MybatisAutoConfiguration {
    
    

Include content

  • @ConditionalOnClass SqlSessionFactory.class
  • DataSource @AutoConfigureAfter DataSourceAutoConfiguration.class

SqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
    
    
    // 后处理器
    public void afterPropertiesSet() throws Exception {
    
    
        // 此处主要是创建默认的 DefaultSqlSessionFactory、DefaultSqlSession 非线程安全
        this.sqlSessionFactory = buildSqlSessionFactory();
    }
    // 监听ApplicationEvent
    public void onApplicationEvent(ApplicationEvent event) {
    
    
        if (failFast && event instanceof ContextRefreshedEvent) {
    
    
            this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
        }
    }
}

DataSourceAutoConfiguration

@Configuration
@ConditionalOnClass({
    
     DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({
    
     DataSourcePoolMetadataProvidersConfiguration.class,
		DataSourceInitializationConfiguration.class })
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 })
	//可以通过配置spring.datasource自动装配上述几种数据库连接池
    protected static class PooledDataSourceConfiguration {
    
    
	}
}

SqlSessionTemplate

@Bean
@ConditionalOnMissingBean
// 线程安全的,Spring's Transaction Manager
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    
    
    ExecutorType executorType = this.properties.getExecutorType();
    if (executorType != null) {
    
    
        return new SqlSessionTemplate(sqlSessionFactory, executorType);
    } else {
    
    
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    // 创建SqlSessionTemplate
    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {
    
    
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        // 创建代理对象由代理对象执行数据库操作
        this.sqlSessionProxy = (SqlSession) newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[] {
    
     SqlSession.class },
            new SqlSessionInterceptor());
    }
    // 代理对象,具体执行的操作
    private class SqlSessionInterceptor implements InvocationHandler {
    
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
            // 获取 sqlsession,重点
            SqlSession sqlSession = getSqlSession(
                SqlSessionTemplate.this.sqlSessionFactory,
                SqlSessionTemplate.this.executorType,
                SqlSessionTemplate.this.exceptionTranslator);
            try {
    
    
                Object result = method.invoke(sqlSession, args);
                if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
    
    
                    // 强制提交
                    sqlSession.commit(true);
                }
                return result;
            } finally {
    
    
                if (sqlSession != null) {
    
    
                    //关闭 session连接
                    closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                }
            }

DataSource data source configuration class

/**
 * @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;
    }

    // 不使用线程池实现
//    @Bean
//    public DataSource dataSource() throws SQLException {
    
    
//        UnpooledDataSource dataSource = new UnpooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/testdb", "root", "123456");
//        return dataSource;
//    }

//    // 采用 MyBatis 默认支持的线程池
//    @Bean
//    public DataSource dataSource() throws SQLException {
    
    
//        PooledDataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/testdb", "root", "123456");
//        return dataSource;
//    }

//    @Bean
//    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    
    
//        return new SqlSessionTemplate(sqlSessionFactory);
//    }
    // druid 相关 filter 和 servlet 配置
//    @Bean
//    public ServletRegistrationBean statViewServlet(){
    
    
//        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//        servletRegistrationBean.addInitParameter("allow","127.0.0.1");  //设置ip白名单
//        servletRegistrationBean.addInitParameter("deny","192.168.0.19");//设置ip黑名单,优先级高于白名单
//        //设置控制台管理用户
//        servletRegistrationBean.addInitParameter("loginUsername","root");
//        servletRegistrationBean.addInitParameter("loginPassword","root");
//        //是否可以重置数据
//        servletRegistrationBean.addInitParameter("resetEnable","false");
//        return servletRegistrationBean;
//    }
//
//    @Bean
//    public FilterRegistrationBean statFilter(){
    
    
//        //创建过滤器
//        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//        //设置过滤器过滤路径
//        filterRegistrationBean.addUrlPatterns("/*");
//        //忽略过滤的形式
//        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
//        return filterRegistrationBean;
//    }
}

Perform query operations

http://localhost:8080/find-all-courses
think.in.spring.boot.mapper.CourseMapper#findAllCourses
DynamicAdvisedInterceptor#intercept
ReflectiveMethodInvocation#proceed
TransactionInterceptor#invoke
TransactionAspectSupport#invokeWithinTransaction
TransactionAspectSupport#createTransactionIfNecessary
### 支持 org.springframework.transaction.jta.JtaTransactionManager
### 和 org.springframework.jdbc.datasource.DataSourceTransactionManager
AbstractPlatformTransactionManager#getTransaction
DataSourceTransactionManager#doGetTransaction
TransactionSynchronizationManager#getResource
TransactionSynchronizationManager#doGetResource
DataSourceTransactionManager#doBegin
TransactionSynchronizationManager#bindResource
AbstractPlatformTransactionManager#prepareSynchronization
TransactionSynchronizationManager#initSynchronization
### 执行细节
MapperProxy#invoke
MapperMethod#execute
SqlSessionTemplate#selectList()
SqlSessionTemplate.SqlSessionInterceptor#invoke
SqlSessionUtils#getSqlSession()
CachingExecutor#query()
BaseExecutor#query()
SqlSessionUtils#closeSqlSession
BaseExecutor#close
TransactionSynchronizationManager#doUnbindResource

SqlSessionUtils#getSqlSession()

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    
    
    // 查询 Resource 中的 SqlSessionHolder
    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
    // 从 holder 去取 SqlSession 存在则返回
    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
    
    
      return session;
    }
    // 创建 SqlSession
    session = sessionFactory.openSession(executorType);
    // 注册 SqlSessionHolder
    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    // 返回 SqlSession 
    return session;
  }

Sqlsession connection management

//管理每个线程的资源和事务同步的代理实现
// 以列表的方式支持资源同步,事务同步必须由事务激活和停用管控 {@link #initSynchronization()} and {@link #clearSynchronization()}
// 事务支持与否主要在于 {@link #isSynchronizationActive}
public abstract class TransactionSynchronizationManager {
    
    

	private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

	private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

	private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
			new NamedThreadLocal<>("Transaction synchronizations");

	private static final ThreadLocal<String> currentTransactionName =
			new NamedThreadLocal<>("Current transaction name");

	private static final ThreadLocal<Boolean> currentTransactionReadOnly =
			new NamedThreadLocal<>("Current transaction read-only status");

	private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
			new NamedThreadLocal<>("Current transaction isolation level");

	private static final ThreadLocal<Boolean> actualTransactionActive =
			new NamedThreadLocal<>("Actual transaction active");

The specific steps are as follows

1558595047460

This sharing includes the automatic assembly of MyBatis in Spring Boot. Related components include DataSource (data source), SqlSessionFactory (sqlsession factory class), SqlSessionTemplate (sqlsession connector), SqlSessionUtils (tool class), etc. The main analysis part includes SqlSession's The related processes of creation, management, reuse, destruction, and subsequent execution of database operations. Because druid is integrated and used as a database connection pool, the initialization of the Datasource and transaction manager will be analyzed in detail in the next article, so stay tuned .

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/90747384