MyBatis 筆記

配置

<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

application.ymljava

spring:
    datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      dbcp2:
        driver-class-name: com.mysql.cj.jdbc.Driver
        password: ***
        url: jdbc:mysql://127.0.0.1:3306/pzx?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
        username: app
        max-total: 1024

Config文件mysql

@Component
@ConfigurationProperties("spring.datasource.dbcp2")
class MySqlConfig {

    var driverClassName = "com.mysql.jdbc.Driver"
    var username = ""
    var password = ""
    var url = ""
    var maxTotal = 0;
    var maxIdel = 0;
    var maxWaitMillis = 0L

    @Bean
    fun dataSource(): BasicDataSource {
        println("BasicDataSource inited: ${url}")
        val dataSource = BasicDataSource()
        dataSource.driverClassName = driverClassName
        dataSource.url = url
        dataSource.username = username
        dataSource.password = password
        dataSource.maxTotal = maxTotal
        dataSource.maxIdle = maxIdel
        dataSource.maxWaitMillis = maxWaitMillis
        dataSource.setValidationQuery("SELECT 1")
        dataSource.testOnBorrow = true
        return dataSource
    }

}


@Component
@AutoConfigureAfter(MySqlConfig::class)
class MyBatisSessionConfig {
    @Bean
    fun mapperScannerConfigurer(): MapperScannerConfigurer {
        val mapperScannerConfigurer = MapperScannerConfigurer()
        //獲取以前注入的beanName爲sqlSessionFactory的對象
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory")
        //指定xml配置文件的路徑
        mapperScannerConfigurer.setBasePackage("pzx.db.mybatis.mapper")
        return mapperScannerConfigurer
    }
}


@Configuration
//加上這個註解,使得支持事務
@EnableTransactionManagement
class MyBatisConfig : TransactionManagementConfigurer {

    @Autowired
    private var dataSource: DataSource? = null

    override fun annotationDrivenTransactionManager(): PlatformTransactionManager {
        return DataSourceTransactionManager(dataSource!!)
    }

    @Bean(name = arrayOf("sqlSessionFactory"))
    fun sqlSessionFactoryBean(): SqlSessionFactory? {
        val bean = SqlSessionFactoryBean()
        bean.setDataSource(dataSource)

        try {
            return bean.`object`
        } catch (e: Exception) {
            e.printStackTrace()
            throw RuntimeException(e)
        }

    }

    @Bean
    fun sqlSessionTemplate(sqlSessionFactory: SqlSessionFactory): SqlSessionTemplate {
        return SqlSessionTemplate(sqlSessionFactory)
    }
}

Mapper文件git

@Mapper
interface CityMapper {
    @Select("select * from s_city where code = #{code}")
    @Results(value = arrayOf(Result(column = "password", property = "password")))
    fun findByCode(@Param("code") code: String): SysCity?
}

調用spring

@Autowired
    lateinit var ds : CityMapper

    @GetMapping("/testMySql")
    fun testMySql(request: HttpServletRequest): String {
        var e = ds.findByCode("110")

        return request.UserId;
    }

源碼跟蹤

關於緩存參考:
https://www.jianshu.com/p/c553169c5921sql

而我想要的緩存是:數據庫

  1. 攔截 query , update
  2. query 時,自定義 cacheKey , 及緩存策略。
  3. update 時,清空緩存。
    參考: https://blog.csdn.net/mingjia1987/article/details/79424272

依次執行:apache

  • MapperMethod.execute -> sqlSession.selectOne
  • SqlSessionTemplate.selectOne
  • DefaultSqlSession.selectOne
  • DefaultSqlSession.selectList ->
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);api

    到這裏, Configuration 出現了。緩存

  • CachingExecutor.query ->
    createCacheKey
    querymybatis

    出如今Sql及CacheKey: 383339099:1114119213:pzx.db.mybatis.mapper.CityMapper.findByCode:0:2147483647:select * from s_city where code = ?:110:SqlSessionFactoryBean
    分爲如下部分: hashcode:checksum:各個部分。 前面的 hashcode:checksum 能夠表示惟一了, 添加後面的部分, 是爲了描述元數據。我的感受後面部分能夠簡化爲: 排序關聯表(主鍵的惟一值) 的方式。惟一值僅在關聯表是一個,且根據主鍵查詢的狀況。

  • CachingExecutor.query ->
    MappedStatement.getCache
    SimpleExecutor.query

    惋惜 MappedStatement.getCache 返回了空。沒走緩存。

  • BaseExecutor.query ->
    PerpetualCache: localCache .getObject
    else queryFromDatabase

    最後執行:
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
    // issue #482
    clearLocalCache();
    }

    默認配置 configuration.localCacheScope = LocalCacheScope.SESSION ,簡單來講,是一次鏈接一個會話,每一個會話有獨立的緩存數據 , 這裏也使用了緩存。也返回了空,由於第二次刷新頁面,是一個新的會話。

    localCache .getObject 是網上說的一級緩存, 也就是說,上面的 MappedStatement.getCache 是二級緩存。 邏輯:
    先從二級緩存查,查不到再從一級緩存查。
    這是有道理的: 由於一級緩存沒法感知外部數據變化,可能有髒數據。那麼若是外部數據因爲 update 等操做,把緩存刪掉,再從一級緩存查,就查出髒數據了。一級緩存的破壞是怎樣進行的? 應該在外部 update 等 更新操做事件後, 把全部關聯的一級緩存清空。
    應該在 update , delete, insert 操做以後, 自動清空全部的相關表的一級緩存, 待驗證。

  • BaseExecutor.queryFromDatabase ->

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }
  • SimpleExecutor.doQuery
  • StatementHandler.query
  • RoutingStatementHandler.query
  • PreparedStatementHandler.query ->
    PreparedStatement.execute
    DefaultResultSetHandler.handleResultSets

    PreparedStatement.execute 是真正的執行。
    DefaultResultSetHandler.handleResultSets 應該是緩存數據的。

  • DefaultResultSetHandler.handleResultSets ->
    handleResultSet ->
    storeObject -> callResultHandler -> 數據保存在 : DefaultResultContext.resultObject -> DefaultResultHandler.handleResult 數據也存在了 DefaultResultHandler.list 中。

生成器

在項目根目錄,建一個 lib 文件夾, 裏面放:

  • mysql-connector-java-6.0.6.jar
  • mybatis-generator-core-1.3.6.jar

.\src\main\resources\generator\generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
  <classPathEntry location=".\lib\mysql-connector-java-6.0.6.jar" />
  <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">

    <!--<plugin type="tk.mybatis.mapper.generator.MapperPlugin">-->
      <!--<property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>-->
      <!--&lt;!&ndash; caseSensitive默認false,當數據庫表名區分大小寫時,能夠將該屬性設置爲true &ndash;&gt;-->
      <!--<property name="caseSensitive" value="true"/>-->
    <!--</plugin>-->


    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                    connectionURL="jdbc:mysql://192.168.3.1:3306/xy_broker"
                    userId="root"
                    password="">
    </jdbcConnection>

    <javaModelGenerator targetPackage="com.xyauto.interact.broker.server.entity" targetProject=".\src\main\java"/>
    <sqlMapGenerator targetPackage="mapper"  targetProject=".\src\main\resources"/>

    <!--<javaClientGenerator targetPackage="com.xyauto.interact.broker.server.dao" targetProject="D:\xycode-git\broker\broker-server\src\main\java" type="XMLMAPPER" />-->

    <table tableName="statistics_clue_broker_day" >
    </table>
  </context>
</generatorConfiguration>

Java -jar .\lib\mybatis-generator-core-1.3.6.jar -configfile .\src\main\resources\generator\generatorConfig.xml -overwrite

日誌

@Bean
    fun abc() : SqlSessionFactory {
        SqlSessionFactory fac = factory.getObject();
        fac.getConfiguration().setLogImpl(MyBatisLog.class);
        return fac;
    }


package com.xingyuanauto.api.pic.mybatis;

import org.apache.ibatis.logging.Log;

/**
 * Created by yuxh on 2018/8/27
 */
public class MyBatisLog implements Log {
    private String action = "";

    public MyBatisLog(String actionClass) {
        String[] ary = actionClass.split("\\.");
        this.action = ary[ary.length - 1];
    }


    @Override
    public boolean isDebugEnabled() {
        return true;
    }

    @Override
    public boolean isTraceEnabled() {
        return true;
    }

    @Override
    public void error(String s, Throwable throwable) {
        System.out.println(s);
    }

    @Override
    public void error(String s) {
        System.out.println(s);
    }

    @Override
    public void debug(String s) {
        System.out.println(s);
    }

    @Override
    public void trace(String s) {
        System.out.println(s);
    }

    @Override
    public void warn(String s) {
        System.out.println(s);
    }
}

配置

<logger name="java.sql.Connection" level="DEBUG">
              <appender-ref ref="STDOUT"/>
       </logger>
       <logger name="java.sql.Statement" level="DEBUG">
              <appender-ref ref="STDOUT"/>
       </logger>
       <logger name="java.sql.PreparedStatement" level="DEBUG">
              <appender-ref ref="STDOUT"/>
       </logger>
       <logger name="org.apache.ibatis" level="DEBUG">
              <appender-ref ref="STDOUT"/>
       </logger>
       <logger name="java.sql" level="debug">
              <appender-ref ref="STDOUT"/>
       </logger>

設置參數:

mapUnderscoreToCamelCase: true -> 數據庫自動映射到小駝峯字段.

相關文章
相關標籤/搜索