zoukankan      html  css  js  c++  java
  • 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.yml

    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文件

    
    @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文件

    @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?
    }
    

    调用

        @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/c553169c5921

    而我想要的缓存是:

    1. 拦截 query , update
    2. query 时,自定义 cacheKey , 及缓存策略。
    3. update 时,清空缓存。
      参考: https://blog.csdn.net/mingjia1987/article/details/79424272

    依次执行:

    • 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);

      到这里, Configuration 出现了。

    • CachingExecutor.query ->
      createCacheKey
      query

      出现在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

    .srcmain esourcesgeneratorgeneratorConfig.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=".libmysql-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=".srcmainjava"/>
        <sqlMapGenerator targetPackage="mapper"  targetProject=".srcmain
    esources"/>
    
        <!--<javaClientGenerator targetPackage="com.xyauto.interact.broker.server.dao" targetProject="D:xycode-gitrokerroker-serversrcmainjava" type="XMLMAPPER" />-->
    
        <table tableName="statistics_clue_broker_day" >
        </table>
      </context>
    </generatorConfiguration>
    

    Java -jar .libmybatis-generator-core-1.3.6.jar -configfile .srcmain esourcesgeneratorgeneratorConfig.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 -> 数据库自动映射到小驼峰字段.

  • 相关阅读:
    BPM系统终于告一段落
    淘宝SOA框架dubbo学习(5)--结果缓存
    淘宝SOA框架dubbo学习(3)--搭建监控中心
    淘宝SOA框架dubbo学习(4)--参数验证
    淘宝SOA框架dubbo学习(1)--first demo
    淘宝SOA框架dubbo学习(2)--搭建Zookeeper注册中心服务
    SOA Dubbo分布式架构学习
    编程有害身体健康 且Coding且珍惜
    数据库日志收缩大小
    dax 计算某一列重复出现次数
  • 原文地址:https://www.cnblogs.com/newsea/p/8997606.html
Copyright © 2011-2022 走看看