Mybatis详解
1.MyBatis是什么?
- Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高。
- MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
1.1MyBatis优缺点
优点:
- 基于SQL语句编程,灵活性高
- 代码量少,不需要手动开关链接
- 兼容性好
- 提供映射标签,支持对象与数据库字段的关系映射;提供对象关系映射标签,支持对象关系组件维护
- 能够与spring很好的集成
缺点:
- sql语句编写工作量大,当字段多、表多时很麻烦
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
2.关联对象查询
对于查询而言,除了使用resultType指定返回记录类型,也可以使用resultMap进行查询结果的映射。
resultType: 查询结果是单表数据(单一实体),或者查询的列名和实体属性能一一对应, 一般用于简单结果集的映射配置
resultMap: 查询是多表数据(有多个实体),或者查询的列名和实体属性不能对应(例如:emp _name,empName)一般用于复杂结果集的映射配置
resultMap用于如下两种情况:
- 查询结果的列名与实体属性不对应时,通过resultMap指明列和对象属性的映射关系
- 在嵌套对象的结构中,设置对象的数据
2.1一对一关系
一对一关系(association):一个员工属于一个部门
2.2一对多关系
一对多关系(collection):一个部门有多个员工
3.动态SQL
动态sql标签:if、where、trim、set、foreach、choose
3.1 if标签
根据条件判断拼接SQL语句
注:if标签一般用于非空验证,如上例,若id为空,if标签里的代码,将不会执行,反之,则会 执行。
3.2where标签
where一般和if结合使用,根据参数值动态拼接sql
1.当需要拼接条件的时候,会自动拼接where关键字
2.自动去除第一个条件前面的and关键字
注:where标签会根据情况自动过滤掉前面的and或者or
如果where元素没有按正常套路出牌,我们还是可以通过自定义trim元素来定制我们想要的功能
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
另外,在xml文件中尽量避免写大于,小于,大于等于,小于等于 &
解决方案
3.3trim、set标签
trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除 或者条件查询等操作。
set标签:1.生成set关键字 2.去除最后的逗号
3.4foreach标签
foreach:循环方式生成SQL语句
foreach可以迭代任何对象(数组、集合等)。
当使用可迭代对象或者数组时, index 是当前迭代的次数, item 的值是本次迭代获取的元素。当使用字典(或者 Map.Entry 对象的集合)时,index 是 键, item 是值。 collection 标签可以填 (‘list’,‘array’,‘map’) 。
foreach遍历批量插入
3.5choose(when,otherwise)
choose:类似于switch分支语句,可以根据条件执行某个分支,走了一个分支之后,其他分支不 再执行
<select id="findChoose" resultType="pojo.Class">
select id,cla_name
from class
<where>
<choose>
<when test="name != null">
cla_name = #{name}
</when>
<otherwise>
id = 1
</otherwise>
</choose>
</where>
</select>
注:choose(when,otherwise)标签类似switch(case,default)
3.7sql标签定义通用标签
<sql id="classSql">
select * from class
</sql>
<select id="findOne" resultType="pojo.Class">
<include refid="classSql"></include>
where id = 1;
</select>
4.延迟加载
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载, association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis 配置文 件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
它的原理是,使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截 器方法,比如a.getB().getName(),拦截器 invoke()方法发现a.getB()是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调 用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName()方法的 调用。这就是延迟加载的基本原理。
关联查询加载时机:
- 直接加载:执行完主对象的查询后,马上执行对关联对象的查询
- 侵入式加载:执行完主对象的查询后,不会执行对关联对象的查询,但当访问主对象的详情时,会执行关联对象的查询
- 深度延迟:只有真正访问关联对象的详情才会执行查询语句
1.全局延迟
<!--现在的状态为直接加载,只要查询主记录就查询关联表-->(3.4.1版本之后的直接加载设
置)
<settings>
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--现在的状态为侵入式延迟加载:访问主记录的属性时,才触发关联表查询-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
<!--现在的状态为深度延迟加载,只有访问主记录中关联的对象属性时,才触发关联查询-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2.部分延迟
在关联查询 collection 、 association 标签上添加 fetchType 属性,lazy表示(深度)延迟加 载,eager表示立即加载,指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled
<association property="dept"
autoMapping="true"
javaType="Dept"
select="getDeptByDeptId"
column="dept_id"
fetchType="lazy"> </association>