MyBatisはDruidを統合して、データベーススレッドプール管理を実現します(1)

MyBatisはDruidを統合して、データベーススレッドプール管理を実現します(1)

MyBatisとは

MyBatisは、カスタマイズされたSQL、ストアドプロシージャ、および高度なマッピングをサポートする優れた永続化レイヤーフレームワークです。MyBatisは、ほとんどすべてのJDBCコードとパラメーターの手動設定、および結果セットの取得を回避します。MyBatisは、単純なXMLまたは注釈を使用して、ネイティブタイプ、インターフェイス、およびJava POJO(プレーンオールドJavaオブジェクト)をデータベース内のレコードとして構成およびマッピングできます。

MyBatisの主要コンポーネント

  • 構成
  • sqlsession
  • エグゼキュータ

sqlsessionは、構成構成(注釈付きのSQLまたはxml構成ファイル)を解析し、対応するエグゼキューターを使用してデータベース操作を実行し、実行された結果セットを処理して、表示処理のためにアプリケーション層に返します。

詳細については、上記の記事を参照してください

MyBatisの深い理解と使用-MyBatisキャッシュシステム

MyBatisの深い理解と使用-TypeHandler

MyBatisの深い理解と使用-MyBatis

Druidとは何ですか?

Druidは、Java言語で最高のデータベース接続プールです。Druidは、強力な監視と拡張機能を提供できます。

詳細については、上記の記事を参照してください。

ソースコード関連のmaven依存関係を共有する

<!-- 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とdruidの部分構成

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

ソースコード分析

自動組み立てプロセス

ソースコードエントリ

spring.factories

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

読み込みプロセス

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports()アセンブリorg.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

組立条件

@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 {
    
    

コンテンツを含める

  • @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データソース構成クラス

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

クエリ操作を実行する

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接続管理

//管理每个线程的资源和事务同步的代理实现
// 以列表的方式支持资源同步,事务同步必须由事务激活和停用管控 {@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");

具体的な手順は次のとおりです。

1558595047460

この共有には、Spring BootでのMyBatisの自動アセンブリが含まれます。関連コンポーネントには、DataSource(データソース)、SqlSessionFactory(sqlsessionファクトリクラス)、SqlSessionTemplate(sqlsessionコネクタ)、SqlSessionUtils(ツールクラス)などがあります。主な分析部分には、SqlSessionが含まれます。データベース操作の作成、管理、再利用、破棄、およびその後の実行の関連プロセス。druidは統合され、データベース接続プールとして使用されるため、データソースとトランザクションマネージャーの初期化については次の記事で詳しく分析しますので、ご期待ください。 。

より優れた記事

javaの小学生
https://blog.csdn.net/shang_xs

MyBatis関連の詳細

MyBatisの詳細な理解と使用-MyBatisキャッシュシステム
https://blog.csdn.net/shang_xs/article/details/86656353MyBatisの
詳細な理解と使用-MyBatisキャッシュシステム
https://blog.csdn.net/shang_xs/article/details / 86656353MyBatisの
深い理解と使用-TypeHandlerhttps //blog.csdn.net/shang_xs/article/details/86656173

SpringはTomcatとJndiを組み合わせて、データソースの外部構成を実現します

https://blog.csdn.net/shang_xs/article/details/90599810
Springは、JbossとJndiを組み合わせて、データソースの外部構成を実装します
https://blog.csdn.net/shang_xs/article/details/90610242

サーブレットの詳細な研究と理解(1)
https://blog.csdn.net/shang_xs/article/details/90371068のIn
サーブレットの深さ研究と理解(2)
https://blog.csdn.net/shang_xs/article/details/90376489

完全なコードと関連する依存関係については、GitHubを参照してください。

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

公式アカウントの推奨

ここに写真の説明を挿入

おすすめ

転載: blog.csdn.net/shang_xs/article/details/90747384