<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
而我想要的缓存是:数据库
依次执行:apache
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; }
PreparedStatementHandler.query ->
PreparedStatement.execute
DefaultResultSetHandler.handleResultSets
PreparedStatement.execute 是真正的执行。
DefaultResultSetHandler.handleResultSets 应该是缓存数据的。
DefaultResultSetHandler.handleResultSets ->
handleResultSet ->
storeObject -> callResultHandler -> 数据保存在 : DefaultResultContext.resultObject -> DefaultResultHandler.handleResult 数据也存在了 DefaultResultHandler.list 中。
在项目根目录,建一个 lib 文件夹, 里面放:
.\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"/>--> <!--<!– caseSensitive默认false,当数据库表名区分大小写时,能够将该属性设置为true –>--> <!--<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 -> 数据库自动映射到小驼峰字段.