一、MyBatis概念
1、为什么需要ORM框架?
传统的JDBC编程存在的弊端:
工作量大,操作数据库至少要5步;
业务代码和技术代码耦合;
连接资源手动关闭,带来了隐患
2、ORM是什么?
对象关系映射(ORM Obeject Relational Mapping),ORM模型就是数据库的表与简单Java对象(POJO)的映射模型,它主要解决数据库数据和POJO对象的相互映射;
ORM带来的好处:
更加贴合面向对象的编程语意,Java程序员喜欢的姿势;
技术和业务解耦,Java程序员无需对数据库相关的知识深入了解
妈妈再也不用担心我,不释放数据库连接资源了
3、ORM框架两大霸主
4、Mybatis是什么?
Mybatis前身是iBatis,其源于“Internet”和“ibatis”的组合,本质是一种半自动的ORM框架,除了POJO 和映射关系之外,还需要编写SQL语句。Mybatis映射文件三要素:SQL、映射规则、POJO
二、Mybatis快速入门
1)加入mybatis的依赖
2)添加mybatis的配置文件
3)场景介绍
4)编写实体类、mapper接口以及mapper xml文件;
5)编写实例代码
SqlSessionFactoryBuilder:读取配置信息创建SqlSessionFactory,建造者模式,方法级别生命周期;SqlSessionFactory:创建Sqlsession,工厂单例模式,存在于程序的整个生命周期。
SqlSession:代表一次数据库连接,可以直接发送SQL执行,也可以通过调用Mapper访问数据库;线程不安全,要保证线程独享(方法级)。
SQL Mapper:由一个Java接口和XML文件组成,包含了要执行的SQL语句和结果集映射规则。方法级别生命周期。
1、Mybatis配置
第一种方式用的推荐使用,类文件和mapper文件可以不需要放在一个文件夹中,xml文件也不会和java文件混合在一起。
2、Mybatis配置 environments
Environment:元素是配置一个数据源的开始,属性id是它的唯一标识
transactionManager元素配置数据库事务,其中type属性有三种配置方式:
- jdbc,采用jdbc的方式管理事务;
- managed,采用容器的方式管理事务,在JNDI数据源中使用;
- 自定义,自定义数据库事务管理办法;
dataSource元素配置数据源连接信息,type属性是连接数据库的方式配置,有四种配置方式:
- UNPOOLED 非连接池方式连接
- POOLED 使用连接池连接
- JNDI 使用JNDI数据源
- 自定义数据源
3、Mybatis配置 mapper
注意:第一种方式用的推荐使用,类文件和mapper文件可以不需要放在一个文件夹中,xml文件也不会和java文件混合在一起。
4、基于xml配置的映射器:
cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
5、select元素
1)自动映射:
前提:SQL列名和JavaBean的属性是一致的;
自动映射等级autoMappingBehavior设置为PARTIAL,需要谨慎使用FULL;
使resultType;如果列名和JavaBean不一致,但列名符合单词下划线分割,Java是驼峰命名法,则mapUnderscoreToCamelCase可设置为true;
2)传递多个查询入参:
使用map传递参数;可读性差,导致可维护性和可扩展性差,杜绝使用;
使用注解传递参数;直观明了,当参数较少一般小于5个的时候,建议使用;
使用Java Bean的方式传递参数;当参数大于5个的时候,建议使用;
6、resultType还是resultMap
1)resultType元素
resultType:当使用resultType做SQL语句返回结果类型处理时,对于SQL语句查询出的字段在相应的
pojo中必须有和它相同的字段对应,而resultType中的内容就是pojo在本项目中的位置。
自动映射
·前提:SQL列名和JavaBean的属性是一致的;
·使用resultType,如用简写需要配置typeAliases (别名);
·如果列名和JavaBean不一致,但列名符合单词下划线分割,Java是驼峰命名法,则
mapUnderscoreToCamelCase可设置为true;
2)resultMap元素 属性
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,在对复杂语句进行联合映射的时候,它很可能可以代替数千行的同等功能的代码。
ResultMap 的设计思想是,简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。
Id:当前命名空间中的一个唯一标识,用于标识一个result map.
Type:类的完全限定名, 或者一个类型别名 (内置的别名可以参考上面的表格).
autoMapping:如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属
性会覆盖全局的属性 autoMappingBehavior。默认值为:unset。
使用场景:
·字段有自定义的转化规则
·复杂的多表查询
3)resultMap元素 子元素
Id:一个 ID结果;标记出作为ID的结果可以帮助提高整体性能
Result:注入到字段或JavaBean属性的普通结果
Association:一个复杂类型的关联;许多结果将包装成这种类型
嵌套结果映射:关联可以指定为一个resultMap元素,或者引用一个
Collection:一个复杂类型的集合
嵌套结果映射:集合可以指定为一个resultMap元素,或者引用一个
Discriminator:使用结果值来决定使用哪个resultMap
·Case:基于某些值的结果映射
·嵌套结果映射:一个 case 也是一个映射它本身的结果,因此可以包含很多相 同的元素,或者它可以参照一个外部的 resultMap
7、id & result
id 和 result 都将一个列的值映射到一个简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段,两者之间的唯一不同是, id 表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候。
Property:POJO中映射到列结果的字段或者属性。如果POJO的属性匹配的是存在的,和给定SQL列名(column元素)相同的,那么MyBatis就会自动映射;
Column:SQL中的列名,或者是列的别名。一般情况下,这和 传递给 resultSet.getString(columnName) 方法的参数一样。
javaType:配置的Java的类;
jdbcType:配置的数据库的类型;
typeHandler:类型处理器,使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是一个类型处理 器实现类的完全限定名,或者是类型别名。
8、constructor构造方法配置
一个pojo不存在没有参数的构造方法,就需要使用constructor;
为了通过名称来引用构造方法参数,你可以添加 @Param 注解,指定参数名称的前提下,以任意顺序编写 arg 元素
<constructor>
<idArg column="id" javaType="int" />
<arg column="user_name" javaType="String" />
</constructor>
9、insert, update 和 delete
Id:命名空间中的唯一标识符,可被用来代表这条语句。
parameterType:将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为MyBatis可以通过TypeHandler推断出具体传入语句的参数,默认值为unset。
flushCache:将其设置为true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。
Timeout:这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为unset(依赖驱动)。
statementType:STATEMENT,PREPARED或CALLABLE的一个。这会让MyBatis分别使用Statement,PreparedStatement或CallableStatement,默认值:PREPARED。
useGeneratedKeys:(仅对insert和update有用)这会令MyBatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像MySQL和SQL Server这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty:(仅对insert和update有用)唯一标记一个属性,MyBatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn:(仅对insert和update有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
databaseId:如果配置了databaseIdProvider,MyBatis会加载所有的不带databaseId或匹配当前 databaseId的语句;如果带或者不带的语句都有,则不带的会被忽略。
10、selectKey元素
keyProperty:selectKey语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn:匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType:结果的类型。MyBatis通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的Object或一个 Map。
Order:这可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先选择主键,设置keyProperty然后执行插入语句。如果设置为AFTER,那么先执行插入语句,然后是 selectKey元素-这和像Oracle的数据库相似,在插入语句内部可能有嵌入索引调用。
statementType:与前面相同,MyBatis支持STATEMENT,PREPARED和CALLABLE语句的映射类型,分别代表PreparedStatement和CallableStatement类型。
<selectKey keyProperty=“id” order= " Before" resultType="int">
select SEQ_ID.nextval from dual
</selectKey>
11、怎么传递多个参数?
使用map传递参数;可读性差,导致可维护性和可扩展性差,杜绝使用;
使用注解传递参数;直观明了,当参数较少一般小于5个的时候,建议使用;
使用Java Bean的方式传递参数;当参数大于5个的时候,建议使用;
12、怎么样获取主键?
insert标签相关属性
useGeneratedKeys:(仅对insert和update有用)这会令MyBatis 使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty:(仅对insert和update有用)唯一标记一个属性,MyBatis会通过getGeneratedKeys 的返回值或者通过insert语句的selectKey子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
13、SQL的参数
sql元素:用来定义可重用的 SQL 代码段,可以包含在其他语句中;
参数:向sql语句中传递的可变参数
预编译 #{}:将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,能够很大程度防止sql注入;
传值 ${}:传入的数据直接显示生成在sql中,无法防止sql注入;
表名、选取的列是动态的,order by和in操作, 可以考虑使用$
注意:两者区别在于传入的参数 是否加了 ‘’引号,#是有占位符 ? 的 $是直接传入的参数
14、动态SQL
1)动态sql元素
If: 判断语句 单条件分支判断。
choose、when、otherwise:相当于java的case when 多条件分支判断。
Trim、where、set:辅助元素 用于处理sql拼装问题。
Foreach:循环语句 在in语句等列举条件常用,常用于实现批量操作。
2)批量操作
通过foreach动态拼装SQL语句
使用BATCH类型的excutor
15、注解方式配置
注解方式就是将SQL语句直接写在接口上,对于需求比较简单的系统,效率较高。缺点在于,每次修改sql语句都要编译代码,对于复杂的sql语句可编辑性和可读性都差,一般不建议使用这种配置方式;
@Select、@Results、@Insert、@Update、@Delete
三、代码生成器
1、Mybatis Generator (MBG)
MyBatis Generator:MyBatis 的开发团队提供了一个很强大的代码生成器,代码包含了数据库表对应的实体 类 、Mapper 接口类、 Mapper XML 文件和 Example 对象等,这些代码文件中几乎包含了全部的单表操作方法,使用 MBG 可以极大程度上方便我们使用 MyBatis,还可以减少很多重复操作。
generatorConfiguration – 根节点
properties – 用于指定一个需要在配置中解析使用的外部属性文件;
classPathEntry - 在MBG工作的时候,需要额外加载的依赖包;
context -用于指定生成一组对象的环境
• property (0 个或多个) - 设置一些固定属性
• plugin (0 个或多个)- 定义一个插件,用于扩展或修改通过 MBG 生成的代码
• commentGenerator (0 个或 1 个) - 该标签用来配置如何生成注释信息
• jdbcConnection ( 1 个)- 必须要有的,使用这个配置链接数据库
• javaTypeResolver ( 0 个或 1 个) - 指定 JDBC 类型和 Java 类型如何转换
• javaModelGenerator ( 1 个) - java模型创建器
• sqlMapGenerator (0 个或 1 个)- 生成SQL map的XML文件生成器
• javaClientGenerator (0 个或 1 个)- 生成Mapper接口
例如: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" >
<!--
1.从命令提示符 使用 XML 配置文件,使用场景:对逆向工程定制较少,项目工程结构比较复杂的情况
java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml
使用场景:对逆向工程定制较多,项目工程结构比较单一的情况:
2. 作为 Maven Plugin 命令: mvn mybatis-generator:generate
3. 从另一个 Java 程序 使用 XML 配置文件
-->
<generatorConfiguration>
<!-- 引入配置文件 -->
<properties resource="db.properties" />
<!-- 制定驱动的位置:D:/tools/mybatis-generator/mysql-connector-java-5.1.18.jar -->
<classPathEntry location="${class_path}" />
<!-- context:生成一组对象的环境
id: 必选,上下文id,用于在生成错误时提示
defaultModelType:指定生成对象的样式
1,conditional:类似hierarchical;
2,flat:所有内容(主键,blob)等全部生成在一个对象中,推荐使用;
3,hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class) targetRuntime:
1,MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample
2,MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample
-->
<context id="context1" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="${jdbc_driver}" connectionURL="${jdbc_url}" userId="${jdbc_username}" password="${jdbc_password}" />
<!-- java模型创建器,是必须要的元素 负责:1,key类(见context的defaultModelType);2,java类;3,查询类
targetPackage:生成的类要放的包,真实的包受enableSubPackages属性控制;
targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录
-->
<javaModelGenerator targetPackage="com.chj.mybatis.entity" targetProject="src/main/java" />
<!-- 生成SQL map的XML文件生成器,
targetPackage:生成的类要放的包,真实的包受enableSubPackages属性控制;
targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,MBG不会自动建目录
-->
<sqlMapGenerator targetPackage="." targetProject="src/main/resources/sqlmapper" />
<!-- 对于mybatis来说,即生成Mapper接口,注意,如果没有配置该元素,那么默认不会生成Mapper接口
type:选择怎么生成mapper接口(在MyBatis3/MyBatis3Simple下):
1,ANNOTATEDMAPPER:会生成使用Mapper接口+Annotation的方式创建(SQL生成在annotation中),不会生成对应的XML;
2,MIXEDMAPPER:使用混合配置,会生成Mapper接口,并适当添加合适的Annotation,但是XML会生成在XML中;
3,XMLMAPPER:会生成Mapper接口,接口完全依赖XML;
注意,如果context是MyBatis3Simple:只支持ANNOTATEDMAPPER和XMLMAPPER
-->
<javaClientGenerator targetPackage="com.chj.mybatis.mapper" targetProject="src/main/java" type="XMLMAPPER" />
<!-- shema 数据库 tableName表名 tableName="%"表示生成所有表对应的映射关系-->
<table schema="mybatis" tableName="%" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
<!-- <table schema="${jdbc_username}" tableName="t_user"
enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
2、怎么运行MGB
1)从命令提示符 使用 XML 配置文件
java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml
2)使用场景:对逆向工程定制较少,项目工程结构比较复杂的情况作为:
Maven Plugin mvn mybatis-generator:generate
3)从另一个 Java 程序 使用 XML 配置文件使用场景:对逆向工程定制较多,项目工程结构比较单一的情况。
四、关联查询
在关系型数据库中,我们经常要处理一对一 、 一对多的关系 。 例如, 一辆汽车需要有一个引擎,这是一对一的 关系。 一辆汽车有 4 个或更多个轮子,这是一对多的关系 。关联元素就是专门用来处理关联关系的;
关联元素:
association 一对一关系
collection 一对多关系
discriminator 鉴别器映射
关联方式:
嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集
- 一对一
1.1、一对一嵌套结果
association标签:嵌套结果方式 常用属性:
- property:对应实体类中的属性名,必填项。
- javaType:属性对应的 Java 类型 。
- resultMap:可以直接使用现有的 resultMap ,而不需要在这里配置映射关系。
- columnPrefix:查询列的前缀,配置前缀后,在子标签配置 result 的 column 时可以省略前缀
Tips:
- resultMap可以通过使用extends实现继承关系,简化很多配置工作量;
- 关联的表查询的类添加前缀是编程的好习惯;
- 通过添加完整的命名空间,可以引用其他xml文件的resultMap;
示例代码如下:
<select id="selectUserPosition1" resultMap="userAndPosition1">
select user_name,real_name,sex,mobile,email,a.note,
b.id post_id,b.post_name,b.note post_note
from t_user a,t_position b
where a.position_id = b.id
</select>
1.2、一对一 嵌套查询
association标签:嵌套查询方式 常用属性:
- select :另 一个映射查询的 id, MyBatis 会额外执行这个查询获取嵌套对象的结果 。
- column :列名(或别名),将主查询中列的结果作为嵌套查询的 参数。
- fetchType :数据加载方式,可选值为 lazy 和 eager,分别为延迟加载和积极加载 ,这个配置会覆盖全局的 lazyLoadingEnabled 配置;
Tips:“N+1 查询问题”:
概括地讲,N+1 查询问题可以是这样引起的:
·你执行了一个单独的 SQL 语句来获取结果列表(就是“+1”)。
·对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。
这个问题会导致成百上千的 SQL 语句被执行。这通常不是期望的。
解决办法:使用“fetchType=lazy”并且全局setting进行改善:
<setting name="aggressiveLazyLoading" value="false"/>
示例代码:
<select id="selectUserPosition2" resultMap="userAndPosition2">
select a.id, a.user_name,a.real_name, a.sex,a.mobile, a.position_id from t_user a
</select>
<!-- 关联查询条件 -->
<resultMap id="userAndPosition2" extends="BaseResultMap" type="TUser">
<association property="position" column="position_id" select="com.chj.mybatis.mapper.TPositionMapper.selectByPrimaryKey" />
</resultMap>
2、一对多
collection支持的属性以及属性的作用和association完全相同
mybatis会根据id标签,进行字段的合并,合理配置好ID标签可以提高处理的效率;
Tips:如果要配置一个相当复杂的映射,一定要从基础映射开始配置,每增加一些配置就进行对应的测试,在循序渐进的过程中更容易发现和解决问题。
示例代码如下:一对多 嵌套结果查询
<!-- 一对多关系 嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型 -->
<resultMap id="userAndJobs1" extends="BaseResultMap" type="TUser">
<collection property="jobs" ofType="com.chj.mybatis.entity.TJobHistory">
<result column="comp_name" property="compName" jdbcType="VARCHAR" />
<result column="years" property="years" jdbcType="INTEGER" />
<result column="title" property="title" jdbcType="VARCHAR" />
</collection>
</resultMap>
<!-- 一对多 嵌套结果查询 -->
<select id="selectUserJobs1" resultMap="userAndJobs1">
select a.id,a.user_name,a.real_name,a.sex,a.mobile,b.comp_name,b.years,b.title
from t_user a, t_job_history b
where a.id = b.user_id
</select>
一对多 嵌套查询:
<!-- 一对多 嵌套查询 -->
<resultMap id="userAndJobs2" extends="BaseResultMap" type="TUser">
<collection property="jobs" fetchType="lazy" column="id" select="com.chj.mybatis.mapper.TJobHistoryMapper.selectByUserId" />
</resultMap>
<select id="selectUserJobs2" resultMap="userAndJobs2">
select a.id,a.user_name,a.real_name,a.sex,a.mobile from t_user a
</select>
3、多对多
先决条件一:多对多需要一种中间表建立连接关系;
先决条件二:多对多关系是由两个一对多关系组成的,一对多可以也可以用两种方式实现;
@Test
public void testManyToMany() {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapperExt mapper = sqlSession.getMapper(TUserMapperExt.class);
// 4.执行查询语句并返回结果
//嵌套结果
List<TUser> list = mapper.selectUserRole();
for (TUser tUser : list) {
System.out.println("tUser.getRoles().size=="+tUser.getRoles().size());
}
// 嵌套查询
TRoleMapper roleMapper = sqlSession.getMapper(TRoleMapper.class);
List<TRole> roles = roleMapper.selectRoleandUsers();
System.out.println("================主表查询结束=====================");
for (TRole tRole : roles) {
System.out.println("tRole.getUsers()=="+tRole.getUsers());
}
}
Sql语句:
<!-- 多对多查询 嵌套结果-->
<resultMap id="userRoleInfo" type="TUser" extends="BaseResultMap">
<collection property="roles" ofType="TRole" columnPrefix="role_">
<result column="id" property="id" />
<result column="Name" property="roleName" />
<result column="note" property="note" />
</collection>
</resultMap>
<select id="selectUserRole" resultMap="userRoleInfo">
select a.id,
a.user_name,
a.real_name,
a.sex,
a.mobile,
a.position_id,
b.role_id,
c.role_name,
c.note role_note
from t_user a,
t_user_role b,
t_role c
where a.id = b.user_id AND
b.role_id = c.id
</select>
<!-- 多对多查询 嵌套查询-->
<resultMap id="RoleandUsers" type="TRole" extends="BaseResultMap">
<collection property="users" fetchType="lazy" column="id" select="com.chj.mybatis.mapper.TUserMapperExt.selectUserByRoleId"></collection>
</resultMap>
<select id="selectRoleandUsers" resultMap="RoleandUsers">
select
<include refid="Base_Column_List" />
from t_role
</select>
<!-- 多对多 嵌套查询 -->
<select id="selectUserByRoleId" resultMap="userRoleInfo">
select
<include refid="Base_Column_List" />
from t_user a,
t_user_role b
where a.id = b.user_id and
b.role_id = #{id}
</select>
运行结果:
4、discriminator鉴别器映射
在特定的情况下使用不同的pojo进行关联,鉴别器元素就是被设计来处理这个情况的。鉴别器非常容易理解,因为它的表现很像 Java 语言中的 switch 语句;
discriminator标签常用的两个属性如下:
column:该属性用于设置要进行鉴别比较值的列 。
javaType:该属性用于指定列的类型,保证使用相同的Java类型来比较值。
discriminator标签可以有1个或多个case 标签,case标签包含以下三个属性:
value:该值为discriminator指定column用来匹配的值 。
resultMap:当column的值和value的值匹配时,可以配置使用resultMap指定的映射,resultMap优先级高于resultType。
resultType:当column的值和value的值匹配时,用于配置使用resultType指定的映射。
鉴别器查询代码示例:
<!-- 鉴别器映射 鉴别器非常容易理解,因为它的表现很像 Java 语言中的 switch 语句 -->
<resultMap id="userAndHealthReportMale" extends="userAndHealthReport" type="TUser">
<!-- 一对多 property="healthReports"(List<HealthReport> healthReports) 对应实体类中的属性名,必填项。-->
<collection property="healthReports" column="id"
select= "com.chj.mybatis.mapper.THealthReportMaleMapperExt.selectByUserId"></collection>
</resultMap>
<resultMap id="userAndHealthReportFemale" extends="userAndHealthReport" type="TUser">
<!-- 一对多 property="healthReports"(List<HealthReport> healthReports) 对应实体类中的属性名,必填项。-->
<collection property="healthReports" column="id"
select= "com.chj.mybatis.mapper.THealthReportFemaleMapperExt.selectByUserId"></collection>
</resultMap>
<!-- 根据<case value="1" 来选择需要查询的 resultMap -->
<resultMap id="userAndHealthReport" extends="BaseResultMap" type="TUser">
<discriminator column="sex" javaType="int">
<case value="1" resultMap="userAndHealthReportMale"/>
<case value="2" resultMap="userAndHealthReportFemale"/>
</discriminator>
</resultMap>
<select id="selectUserHealthReport" resultMap="userAndHealthReport">
select <include refid="Base_Column_List" />
from t_user a
</select>
五、Mybatis缓存
1、一级缓存
一级缓存 (也叫应用缓存):MyBatis 包含一个非常强大的查询缓存特性,使用缓存可以使应用更快地获取数据,避免频繁的数据库交互。
1)一级缓存默认会启用,想要关闭一级缓存可以在select标签上配置flushCache=“true”;
2)一级缓存存在于 SqlSession 的生命周期中,在同一个 SqlSession 中查询时, MyBatis 会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个 Map对象中。如果同一个 SqlSession 中执行的方法和参数完全一致,那么通过算法会生成相同的键值,当 Map 缓存对象中己经存在该键值时,则会返回缓存中的对象;
3)任何的 INSERT 、UPDATE 、 DELETE 操作都会清空一级缓存;
2、二级缓存
二级缓存 (也叫应用缓存):
二级缓存存在于SqlSessionFactory的生命周期中,可以理解为跨sqlSession;缓存是以namespace为单位的,不同namespace下的操作互不影响。
setting参数cacheEnabled,这个参数是二级缓存的全局开关,默认值是true,如果把这个参数设置为false,即使有后面的二级缓存配置,也不会生效;
要开启二级缓存,你需要在你的 SQL 映射文件中添加配置:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
字面上看就是这样,这个简单语句的效果如下:
• 映射语句文件中的所有 select 语句将会被缓存。
• 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
• 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
• 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
• 缓存会存储列表集合或对象(无论查询方法返回什么)的 512个引用。
• 缓存会被视为是 read/write(可读/可写)的缓存;
注意:
使用二级缓存容易出现脏读,建议避免使用二级缓存,在业务层使用可控制的缓存代替更好;