MyBatis是一种半自动映射的框架。是目前较为流行的Java ORM框架。(ORM模型是指数据库的表与Java的POJO的映射关系模型,解决之间的相互映射。)本文主要是我在学习了《深入浅出MyBatis技术原理与实战》后的自我总结。
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="true"/> <setting name="autoMappingBehavior" value="FULL"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25000"/> <setting name="logImpl" value="log4j"/> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>
|
这是简单Mybatis的设置。依然还有许多属性我们没有提到。在我们的设置中,autoMappingBehavior
是有三种设置:NONE(取消自动映射)、PARTIAL(只会映射没有定义嵌套结果集映射的结果集,在缺省配置的情况下默认)、FULL;而defaultExecutorType
表示执行器executor类型,分为三种:SIMPLE(普通执行器,默认情况下是SIMPLE)、REUSE(执行器会重用预处理语句prepared statements)、BATCH(执行器会重用语句并执行批量更新)。
在configuration中还会涉及其他属性,常用的有typeAliases(类型命名)、typeHandler(类型处理器)、plugins(插件)等。而对于typeHandler的配置里,又有javaType与jdbcType,typeHandler就是解决其转换的问题。
MyBatis-Spring
一般情况下,我们大多数情况下是在Spring中使用MyBatis,即需要配置MyBatis-Spring。分为五步进行配置:
- 配置数据源
- 配置SqlSessionFactory
- 配置SqlSessionTemple(使用Mapper接口编程方式,这儿的配置就隐藏了)
- 配置Mapper
- 事务处理
先配置数据源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="#{jdbc['jdbc.url']}"/> <property name="username" value="#{jdbc['jdbc.username']}"/> <property name="password" value="#{jdbc['jdbc.password']}"/> <property name="minIdle" value="#{jdbc['ds.minIdle']}"/> <property name="maxActive" value="#{jdbc['ds.maxActive']}"/> <property name="initialSize" value="#{jdbc['ds.initialSize']}"/> <property name="maxWait" value="#{jdbc['ds.maxWait']}"/> <property name="timeBetweenEvictionRunsMillis" value="#{jdbc['ds.timeBetweenEvictionRunsMillis']}"/> <property name="minEvictableIdleTimeMillis" value="#{jdbc['ds.minEvictableIdleTimeMillis']}"/> <property name="validationQuery" value="SELECT 1"/> <property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> <property name="poolPreparedStatements" value="false"/> <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/> <property name="filters" value="stat"/> </bean>
|
这儿我们使用的Druid数据源。接下来配置SqlSessionFactory。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:/mybatis-config.xml"/> <property name="mapperLocations" value="classpath:mappers/*.xml"/> <property name="typeAliasesPackage" value="fei.self.model"/> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ximalaya.ops.fei.self.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>
|
这儿的mybatis-config.xml就是我们之前的configuration以及setting的那个文件。并且在这儿,我们配置了自动扫描信息,包括扫描所有的DAO以及Mapper文件。接下来只剩下事务处理的配置了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="reset*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="getExecution*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/> <tx:method name="select*" read-only="true"/> <tx:method name="count*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
<tx:annotation-driven transaction-manager="transactionManager"/>
|
这是最基础的MyBatis-Spring的配置。这部分其实挺无趣的,个人觉得MyBatis最有趣的就是接下来的MyBatis的技术原理以及插件等。关于Mapper的一些在这儿不作罗列了。
动态SQL
所谓动态SQL,指的是一些特殊的MyBatis标签的使用,从而对于SQL的拼装具有动态性的效果。主要是if、choose、trim、foreach以及bind元素这些。这部分其实挺有趣的,可以增加我们对于MyBatis的掌握。这部分的知识在这儿不作罗列,看一些例子都能明白。
MyBatis原理
终于到了重点且有趣的地方,这部分知识可以帮助我们理解MyBatis,然后能写一些好用的插件。
在学习之前需要掌握动态代理,分为JDK动态代理与CGLIB动态代理。
首先,需要构建SqlSessionFactory。第一步,先通过XMLConfigBuilder解析配置文件,存入Configuration类中(这个类里基本保存了所有的配置)。第二步,使用Configuration去构建SqlSessionFactory。对于SqlSessionFactory,这是一个接口,在一般MyBatis中用DefaultSqlSessionFactory的实现类,对于接口的方法都做了实现。
第二个需要掌握的是Mapper映射器。我们提到过,在Configuration中,有所有的配置,当然映射器也在里面。需要了解的是,Mapper映射是通过动态代理的方式实现的。一般映射器里面包含有三部分:MappedStatement:用户保存映射节点;SqlSource:这是MappedStatement的一个属性,一个接口,主要是根据参数和其他规则组装SQL,当然它提供BoundSql;BoundSql:建立SQL和参数的地方。我们一般修改SQL或者参数都是在BoundSql中修改的。对于BoundSql中如何实现多种参数的注入方式,我这儿就不讲解了。
既然有了SqlSessionFactory,那么我们很容易就得到SqlSession了。从Mapper映射器中,我们通过代理对象会进入到MapperMethod的execute方法。然后就能进入SqlSession的方法里了。我们需要了解的是SqlSession里的增删改查方法是如何实现的。
首先SqlSession下有四大对象。1、Executor执行器:用来调度StatementHandler、ParameterHandler、ResultHandler;2、StatementHandler:这个是在SqlSession里最重要的部分,它可以使数据库的Statement,即PreparedStatement执行操作(PreparedStatement接口是继承了Statement接口);3、ParamentHandler:用于SQL的参数处理;4、ResultHandler:用于最后返回数据集的封装。我学到这儿很疑惑这个Satement究竟是什么?Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存在的存储过程的调用。我们一般在插件中使用的是PrepareStatement,这三者对应了三种数据库会话器,SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler。对于着Executor也分为三种SIMPLE、REUSE、BATCH。关于参数处理器以及结果处理器就不提及了。
插件
插件部分,我无法总结清晰,所以给出我的分页插件中重点intercept函数实现的基本流程图。
附
本文主要是个人的一些总结,没有完全梳理MyBatis的流程等,也没有完全涉及MyBatis的所有知识。