Mybatis 随记
1 一对多collection
1.1 嵌套查询,级联关联
一次关联hz+mx信息,Mybatis会自动合并相同的HZ信息
<!-- 查询 部门 + 部门员工 -->
<select id="getDeptById" resultMap="MyDept" >
SELECT
d.id did,
d.dept_name dept_name,
e.id,
e.last_name last_name,
e.email email,
e.gender gender
FROM
tbl_dept d
LEFT JOIN tbl_employee e ON d.id = e.d_id
WHERE
d.id = #{id}
</select>
<resultMap type="com.Department" id="MyDept">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
<!--collection 也可以指定自己的resultMap-->
<!--emps 对应com.Department 类中的属性名-->
<collection property="emps" ofType="com.Employee">
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
1.2 子查询实现
注意图中多列值传递到子查询的实现
https://blog.csdn.net/aodeng110/article/details/82850221

一对一 association
1 级联方式
<resultMap type="com.Department" id="MyDept">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
<result column="last_name" property="obj.lastName"/>
<result column="email" property="obj.email"/>
</resultMap>
2 <association>标签
<resultMap type="com.Department" id="MyDept">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
<association property="obj" type="Other">
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
</association>
</resultMap>
除了以上正常使用,<association>还支持子查询实现+延迟加载。懒加载等待JAVA调用obj对象进行操作时再加载子查询。好处是加快了主查询的速度,且把所有obj对象的映射填充延迟到后边的的一个一个小查询完成。缺点是增加了查询SQL的执行次数。
2 Spring+Mybatis 一级缓存失效
Spring与Mybatis整合后, Mybatis一级缓存(sqlsession级)会失效。整体为无缓存状态。
3 where 配合1=1条件解决动态sql首位and问题
<where>
1 = 1
<choose>
<when test="parentCode != null and parentCode != ''">
and a.parent_code = #{parentCode}
</when>
<otherwise>
and a.tree_level = 0
</otherwise>
</choose>
</where>
WHERE 1 = 1 and u.status != 1
<if test="loginCode != null and loginCode != ''">
and u.login_code = #{loginCode}
</if>
<if test="userName != null and userName != ''">
and u.username = #{userName}
</if>
4 若参数或条件过多将其封装到Map中传入Mapper
Mapper.xml中根据条件拼接动态SQL
<if test="loginCode != null and loginCode != ''">
and u.login_code = #{loginCode}
</if>
<if test="userName != null and userName != ''">
and u.username = #{userName}
</if>
5 Mybatis批量更新数据
第一种方式:这种方式修改的字段值都是一样的。
<update id="updateBatch" parameterType="Map">
update aa set
a=#{fptm},
b=#{csoftrain}
where c in
<foreach collection="cs" index="index" item="item" open="("separator=","close=")">
#{item}
</foreach>
</update>
第二种方式:这种方式可以一次执行多条SQL语句。但是返回的影响行数是最后一条Update语句的,不是总和。mysql5.5以下版本貌似不支持
修改数据库连接配置:&allowMultiQueries=true
比如:jdbc:mysql://XXX:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
<update id="batchUpdate" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update test
<set>
test=${item.test}+1
</set>
where id = #{item.id}
</foreach>
</update>
5 Foreach
index:遍历List时是索引,遍历Map时是Key
模拟case when
<foreach collection="list" item="item" index="index" separator=" " open="case ID" close="end">
when #{item.id,jdbcType=BIGINT} then #{item.updateCode,jdbcType=BIGINT}
</foreach>
6 #{}预编译 ,${}注入sql
可以看一下哦Mapper日志的区别,#{}会作为Parameters,其使用preparedstatement预处理,防止sql注入。
${}在Preparing时直接注入sql语句中,拼接到sql语句中。
<mapper>
update user name=#{name} where id = ${id}
</mapper>
==> Preparing: update user SET name=? where id = 1
==> Parameters: 李雷(String)
<== Updates: 1
7 Java对象与数据库的类型转换
https://blog.csdn.net/u010526028/article/details/74315775
javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName
一定注意大小写,否则在启动时报错Valid properties are javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName
例1:保存时 #{endTime , javaType=“java.util.Date”,jdbcType=“TIMESTAMP” }
显示时<result column="close_time" property="closeTime" javaType="java.util.Date" jdbcType="TIMESTAMP"/>
可以将数据库时间戳与java的Date类型互转(yyyy-MM-dd HH:mm:ss)
使用jdbcType场景:
1 有null数据时,数据库可能识别有误差,可以指定jdbcType=null或数据库类型。
2 有JAVA到数据库类型装换
注意:
1.mysql中是int类型,则mybatis中对应jdbcType=“INTEGER”
1.java中是long类型,则mybatis中对应jdbcType=“INTEGER”,mysql字段类型bigint
开启支持JAVA驼峰命名法
若Mybatis直接使用<resulttype="POJO">设置返回类型,则SQL字段名/别名必须与POJO完全一致才能成功映射。但是Pojo若设置为驼峰命名则需要Mybatis开启驼峰命名的支持,才能实现数据映射。
Mapper增删改方法返回值
可以返回int、Integer、Boolean、Long、void
参数解析
例如mapper接口中有方法,selectByName(@Param("name") String name, Integer id);
Mybatis会解析参数名和索引为Map{ 0:name, 1: 1} ,注意多参数时若没有标注@Param时是只能获取索引不能获取参数名的。
其在<select>标签中通过#{name}、#{param1}来取得两个参数
@MapKey
支持多条记录返回时直接封装到Map中,而不是List。@MapKey设置查询结果中的哪一列作为MAP的key
@MapKey("id")
Map<String,User> selectByName( String name);
<select id="selectByName" resultType="User">
鉴别器<discriminator >
https://blog.csdn.net/ykzhen2015/article/details/51249963
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ykzhen2015.csdn.mapper.EmployeeMapper">
<resultMap id="employeeMap" type="com.ykzhen2015.csdn.pojo.Employee">
<id property="id" column="id" />
<result property="empName" column="emp_name" />
<result property="sex" column="sex" />
<association property="employeeCard" column="id"
select="com.ykzhen2015.csdn.mapper.EmployeeCardMapper.getEmployeeCardByEmpId" />
<collection property="projectList" column="id"
select="com.ykzhen2015.csdn.mapper.ProjectMapper.findProjectByEmpId" />
<!--判断sex 字段的值 0/1 -->
<discriminator javaType="int" column="sex">
<case value="1" resultMap="maleEmployeeMap" />
<case value="2" resultMap="femaleEmployeeMap" />
</discriminator>
</resultMap>
<select id="getEmployee" parameterType="int" resultMap="employeeMap">
select id, emp_name as empName, sex from t_employee where id =#{id}
</select>
<resultMap id="maleEmployeeMap" type="com.ykzhen2015.csdn.pojo.MaleEmployee" extends="employeeMap">
<collection property="prostateList" select="com.ykzhen2015.csdn.mapper.MaleEmployeeMapper.findProstateList" column="id" />
</resultMap>
<resultMap id="femaleEmployeeMap" type="com.ykzhen2015.csdn.pojo.FemaleEmployee" extends="employeeMap">
<collection property="uterusList" select="com.ykzhen2015.csdn.mapper.FemaleEmployeeMapper.findUterusList" column="id" />
</resultMap>
</mapper>
内置参数_parameter和_databaseId
https://blog.csdn.net/u014268482/article/details/80679619
_parameter:代表整个参数:单个参数:_parameter就是这个参数。
多个参数:参数会被封装为一个map:_parameter就是代表这个map 。
_databaseId:如果配置了databaseIdProvider标签,_databaseId 就是代表当前数据库的别名Oracle
PageHelper
重点注意: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md
返回结果集可以用PageInfo包装。可以获得很多有用的分页信息,包括:当前页号,是否有上/下页,当前页应显示所有导航页号等....
https://pagehelper.github.io/docs/howtouse/
//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectAll();
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//排序
private String orderBy;
//由于startRow和endRow不常用,这里说个具体的用法
//可以在页面中"显示startRow到endRow 共size条数据"
//当前页面第一个元素在数据库中的行号
private int startRow;
//当前页面最后一个元素在数据库中的行号
private int endRow;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//第一页
private int firstPage;
//前一页
private int prePage;
//下一页
private int nextPage;
//最后一页
private int lastPage;
//是否为第一页
private boolean isFirstPage = false;
//是否为最后一页
private boolean isLastPage = false;
//是否有前一页
private boolean hasPreviousPage = false;
//是否有下一页
private boolean hasNextPage = false;
//导航页码数
private int navigatePages;
//所有导航页号
private int[] navigatepageNums;
自增主键回填对象
<insert id="insertBook" useGeneratedKeys="true" keyProperty="id">
insert into t_book (b_name,author) values (#{name},#{author});
</insert>
这种方式比较简单,就是在插入节点上添加 useGeneratedKeys 属性,同时设置接收回传主键的keyProperty属性。配置完成后,我们执行一个插入操作,插入时传入一个对象,插入完成后这个对象的 id 就会被自动赋值,值就是刚刚插入成功的id。
Sql执行超时
https://blog.csdn.net/shuimuz_j/article/details/9674427
https://blog.csdn.net/chen846262292/article/details/86526282
1.如果你使用的是HikariCP连接池的话,可以在配置文件设置connetion-timeout这个属性(如application.properties)
2.如果你使用的是其他链接池,同时持久化框架用的是mybatis的话,那可以这样设置。
//全局配置
mybatis.configuration.default-statement-timeout = 1
可以在select/insert/update/delete 操作语句中设置 timeout值(单位s),当sql执行时间超过1s,就会断开操作了,起到保护数据库服务的作用。会抛出SQLTimeoutException
<select id="getXXXX" parameterType="java.lang.String" resultMap="dataMap" timeout="1">
</select>

浙公网安备 33010602011771号