<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 -> 數據庫自動映射到小駝峯字段.