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&amp;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>

 

posted @ 2019-01-07 13:36  sw008  阅读(508)  评论(0)    收藏  举报