Mybatis探究
mybatis应用十分广泛,也十分简单,通过mybatis-generator反射生成对应的model与mapper即可直接使用。hibernate也有一套类似的工具,但使用起来没有mybatis方便:hibernate tools。
mybatis应用
从使用的角度看,我们会先建表(举例):
CREATE SCHEMA IF NOT EXISTS SYSTEM
DEFAULT CHARACTER SET utf8 ;
USE SYSTEM
;
DROP TABLE IF EXISTS about
;
CREATE TABLE IF NOT EXISTS about
(
ID
CHAR(21) NOT NULL,
NAME
VARCHAR(128) NOT NULL,
UPDATE_USER
CHAR(21) NOT NULL,
CREATE_USER
CHAR(21) NOT NULL,
CREATE_TIME
DATETIME(3) NOT NULL,
UPDATE_TIME
DATETIME(3) NOT NULL,
PRIMARY KEY (ID
))
ENGINE = InnoDB;
然后在服务中引入如下三个依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
</dependency>
mysql-connector-java:数据源为mysql(使用其他数据源需要更改为对应的依赖)
mybatis-spring-boot-starter:mybatis依赖(springboot集成的依赖,非springboot需引入相应的版本)
mybatis-generator-core:mybatis-generator生成器(mybatis反射生成必须引入的依赖)
然后配置mybatis-generator.xml配置反射生成的参数配置
最后执行生成对应的接口与实体
1. mybatis-generator
这里先说下mybatis-generator:
配置文件:
<?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>
<properties resource="mybatis.yml"/>
<context id="MysqlTables" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="autoDelimitKeywords" value="true" />
<property name="javaFileEncoding" value="utf-8" />
<property name="beginningDelimiter" value="`" />
<property name="endingDelimiter" value="`" />
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<commentGenerator >
<property name="suppressAllComments" value="false"/><!-- 是否取消注释 -->
<property name="suppressDate" value="true" /> <!-- 是否生成注释代时间戳-->
</commentGenerator>
<jdbcConnection driverClass="${driver-class-name}" connectionURL="${url}"
userId="${data-username}" password="${data-password}" />
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="com.spring.framework.user.database.po" targetProject="src/main/java" >
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.spring.framework.user.database.mapper"
targetProject="src/main/resources" >
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<javaClientGenerator targetPackage="com.spring.framework.user.database.mapper"
targetProject="src/main/java" type="XMLMAPPER" >
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<table tableName="%" enableCountByExample="true" enableUpdateByExample="true"
enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true">
<property name="useActualColumnNames" value="false" />
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
说明:
首先xml规范格式使用的是引入mybatis官网dtd文件,然后往下是generatorConfiguration生成器配置,主要包含数据库的基础配置(autoDelimitKeywords-自动识别关键字,javaFormatter格式化、大小写处理等)、生成实体接口的包路径与对应的表结构配置。
执行器:
配置文件的加载应用通过请求执行开始:
入口:org.mybatis.generator.api.ShellRunner
此类主要功能为执行前的校验(配置文件的格式,必要参数是否存在等),最终会创建生成器执行。
方法主体:
1.加载配置:
String configfile = arguments.get(CONFIG_FILE);
File configurationFile = new File(configfile);
2.读取配置:
Configuration config = cp.parseConfiguration(configurationFile);
3.创建并执行生成器:
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, shellCallback, warnings);
myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables);
4.执行器:
4.1读取配置内容:
4.2数据库映射:
introspectTables()方法:
依据jdbcConnection的配置链接数据库,然后依据table表名配置与数据源schemal配置获取对应信息:
4.3 接口与实体内容的生成:
详细生成方法:
新版本与旧版本的兼容:
会将读取的数据库sqMap信息格式化存储到对象中:
4.4 结果文件生成:
依据获取的数据库信息在配置的文件路径下生成对应的类文件:
分为java类与xml类:
在往下就是底层的文件格式内容读取、校验,然后排版布局、写入等操作。
最终会生成我们熟悉的mapper接口与xml的sqlMap类。
ps:mybatis-generator提供很多功能,以及生成器也有很多内容,这里不赘述,这里仅列下流程,详细大家可以跟进。
2. mybatis
mybatis在应用时,首先是服务启动加载mapper,然后是使用时注入mapper。
mapper加载:
springcloud(springboot)整合mybatis的情况下,启动服务会加载mapperscan:
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {...
通过该注解,在服务启动的时候,实现registerBeanDefinitions()接口:
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
...
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
...
此方法会定义一个类扫描器对指定路径下的包进行扫描,放入spring容器中:
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry)
...
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
其中registerFilters()设置过滤器,doScan()方法就是将class文件放入bean中,这个bean就是mapperFactoryBean:
private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean<Object>();
...
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
definition.setBeanClass(this.mapperFactoryBean.getClass());
mapper应用:
由上面在服务加载时将mapper交由mapperFactoryBean管理,那我们可知mapperFactoryBean继承了SqlSessionDaoSupport并实现了getObject()接口:
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
...
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
...
那么这里说明下:
1.接口InitializingBean在服务启动后进行实例化所有的bean,接口DaoSupport实现了该bean接口,并进行了sqlsession初始化校验,而我们的MapperFactoryBean又继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承了DaoSupport,故服务加载时会对sqlsession进行初始化并管理mapper:
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
2.sqlsessionTemplate:
sqlsession初始化时会创建sqlsessionTemplate对象对session工厂进行管理:
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
sqlsessionTemplate核心代码:
sqlSessionProxy生成代理对象,所有的接口方法CURD都会通过该代理进行处理。
然后当我们请求mapper接口操作时会首先被SqlSessionInterceptor拦截处理:
大致都会经历四步:
1.获取sqlsession
2.根据请求方法进行反射找到具体的方法
3.提交session请求
4.关闭sqlsession
2020!
大家新年快乐呀~~