mybatis进阶(动态sql、关系映射、延迟加载、缓存)

1.sql标签

公共sql块,一般用在查询字段上.

<sql id="allFields">
    uid,uname,uemail,upwd,uphone,create_time,update_time
</sql>

在select标签中通过include包含sql块

<select id="selectByKey" resultType="sysuser">
    select
     <include refid="allFields"></include>
     from sysuser where uid=#{uid}
</select>

2.resultMap标签(重要)

ResultMap标签使用起来偏复杂,用来对实体对象的属性与数据库字段名做映射,同时提供子标签做对象之间的关系映射,进行级联查询操作。

ResultMap 的设计思想是,对于简单的语句不需要配置显式的结果映射(属性名与字段名一致),而对于复杂一点的语句只需要描述它们的关系就行了。

结果集映射标签,把数据库中的字段名映射到某个实体类的成员变量.

   	<!-- id结果集名称	type结果集映射的实体类-->
<resultMap id="sysuserMap" type="sysuser">
   	<!--coleumn列名 property属性名-->
    <id column="uid" property="uid"></id>
  	<result column="user_address" property="uaddress"/>
	<result column="create_time" property="createTime"></result>
	<result column="update_time" property="updateTime"></result>
</resultMap>
    相同字段可以不写

如果字段名与属性名相同,可省了配置,但id不能省.一般都全部配置.

语句中使用resultMap在标签中的resultType更改成resultMap="sysuserMap"

<!--select标签的resultMap属性的值对应resultMap标签的id-->
<select id="selectUserById" parameterType="int" resultMap="sysuserMap">
  		select * from sysuser where uid=#{uid}
</select>

注意:

​ 1.select标签的resultMap属性与resultType属性不能同时出现,resultType属性的值一般是实体类map或简单型;

​ 2.resultMap属性的值必须是resultMap标签的id值。

​ 3.resultMap标签的id子标签用来进行主键列映射;result子标签进行非主键列映射;

3.对象关系映射(重要)

对象之间的关系:分为持有聚合

1.多对一持有关系(用个用户持有一个角色)

A对象持有B对象的引用,A类中有一个成员变量是B类型的.

比如:用户对象持有角色对象,查询用户的时候,查询出用户的角色信息.

方法1:手工进行两次的单表查询,第一次查询用户,第二次查询角色,把查询结果组合起来.掌握(建议)

  • 创建SysuserMapper.java与sysuserMapper.xml
public interface SysuserMapper {
    
    
    public Sysuser selectUserByKey(Integer uid);
}

<select id="selectUserByKey" parameterType="int" resultType="Sysuser">
    select * from sysuser where uid=#{
    
    uid}
</select>
  • 创建SysroleMapper.java与sysroleMapper.xml
public interface SysroleMapper {
    
    
    public Sysrole selectRoleByRid(Integer rid);
}

<select id="selectRoleByRid" parameterType="int" resultType="sysrole">
    select * from sysrole where rid=#{
    
    rid}
</select>
  • 测试,结果组合
SysRoleMapper rm = session.getMapper(SysRoleMapper.class);
SysUserMapper2 um = session.getMapper(SysUserMapper2.class);
//第一次查询用户
Sysuser sysuser = um.selectUserByKey(13);
//第二次查询该用户的角色
Sysrole sysrole = rm.selectRoleByKey(sysuser.getRid());
//组装对象
sysuser.setSrole(sysrole);

方法2:由mybatis进行两次单表查询,使用association标签指定二次查询的位置.掌握(两个mapper.两个映射文件)

property:持有对象的变量名 column:传入二次查询的参数的字段

javaType:持有对象的类型 ,二次查询返回值的类型 select : 二次查询的位置(namespace+id )

<!--select:二次查询的位置namespace.id
    srole:持有对象的变量名
    javaType:持有对象的类型,二次查询的返回值类型
    column:传入二次查询的字段,二次查询需要的参数
    -->
<association property="srole" column="rid" javaType="sysrole"
             select="com.javasm.mapper.SysroleMapper.selectByKey"></association>

<resultMap id="sysuserAndRoleMap" type="sysuser">
    <id column="uid" property="uid"></id>
    <result column="uname" property="uname"></result>
    <result column="uemail" property="uemail"></result>
    <result column="uphone" property="uphone"></result>
    <result column="upwd" property="uped"></result>
    <result column="create_time" property="createTime"></result>
    <result column="update_time" property="updateTime"></result>
    <association property="srole" column="rid" javaType="sysrole" 			   							 select="com.javasm.mapper.SysRoleMapper.selectRoleByKey">
    </association>
</resultMap>

<select id="selectUserAndRoleByUKey" resultMap="sysuserAndRoleMap">
    select * from sysuser where uid = #{uid}
</select>
//角色映射文件中
<select id="selectRoleByKey" parameterType="int" resultType="sysrole">
    select *  from sysrole where rid = #{rid}
</select>

方法3:使用sql语句表级联查询,一次需要的列全查出来,不需要进行二次查询.association不推荐使用(单表操作索引生效,夺多表操作索引失效)复杂的报表分析可以使用(当使用在报表分析的时候直接返回map)

<resultMap id="sysuserAndRoleMap2" type="sysuser">
    <id column="uid" property="uid"></id>
    <result column="uname" property="uname"></result>
    <result column="uemail" property="uemail"></result>
    <result column="uphone" property="uphone"></result>
    <result column="upwd" property="uped"></result>
    <result column="create_time" property="createTime"></result>
    <result column="update_time" property="updateTime"></result>
    <association property="srole" javaType="sysrole" >
        <id column="rid" property="rid"></id>
        <result column="rname" property="rname"></result>
        <result column="rdec" property="rdec"></result>
        <result column="roleCreateTime" property="createTime"></result>
        <result column="roleUpdateTime" property="updateTime"></result>
    </association>
</resultMap>

<select id="selectUserAndRoleByUKey2" resultMap="sysuserAndRoleMap2">
    select u.*,r.rname,r.rdec,r.create_time,r.update_time as roleCreateTime,r.update_time as 	roleUpdateTime from  sysuser u,sysrole r where u.rid=r.rid and u.uid=#{uid}
</select>

2.聚合关系(一个角色聚合了多个用户)

A对象持有了B对象的集合,A类中有一个List集合,集合泛型是B类型的.比如:角色对象聚合了用户对象,查询角色并查询出该角色下的所有用户信息.

使用collection标签进行聚合映射

方法1:手工进行两次的单表查询,把查询结果组合起来.掌握(建议)

方法2:由mybatis进行两次单表查询,使用association标签指定二次查询的位置.掌握(两个mapper.两个映射文件)

<resultMap id="roleAndUsersMap" type="sysrole">
    <id column="rid" property="rid"></id>
    <result column="rname" property="rname"></result>
    <result column="create_time" property="createTime"></result>
    <result column="update_time" property="updateTime"></result>
    <collection property="susers" ofType="sysuser" column="rid"	select="com.javasm.mapper.SysUserMapper2.selectUsersByRoleId">
	</collection>
</resultMap>
<select id="selectRoleAndUserByRid" resultMap="roleAndUsersMap" parameterType="int">
    select *  from sysrole where rid=#{rid};
</select>


//另外一个映射文件
<resultMap id="sysuserMap" type="sysuser">
    <id column="uid" property="uid"></id>
    <result column="uname" property="uname"></result>
    <result column="uemail" property="uemail"></result>
    <result column="uphone" property="uphone"></result>
    <result column="upwd" property="upwd"></result>
    <result column="create_time" property="createTime"></result>
    <result column="update_time" property="updateTime"></result>
</resultMap>
<select id="selectUsersByRoleId" parameterType="int" resultMap="sysuserMap">
    select * from sysuser where rid=#{rid}
</select>

方法3:使用sql语句表级联查询,一次需要的列全查出来,不需要进行二次查询.collection

property:持有对象的变量名 javaType:只有两种list或者set
ofType:集合的泛型类型是什么 column:传入入二次查询的参数的字段

<!--ofType:集合的泛型类型-->
<collection property="susers" ofType="sysuser" column="rid" select="com.javasm.mapper.SysuserMapper2.selectUsersByRoleId"></collection>
<resultMap id="roleAndUsersMap2" type="sysrole">
    <id column="rid" property="rid"></id>
    <result column="rname" property="rname"></result>
    <result column="create_time" property="createTime"></result>
    <result column="update_time" property="updateTime"></result>
    <collection property="susers" ofType="sysuser">
        <id column="uid" property="uid"></id>
        <result column="uname" property="uname"></result>
        <result column="ctime" property="createTime"></result>
        <result column="utime" property="updateTime"></result>
    </collection>
</resultMap>
    <select id="selectRoleAndUserByRid2" resultMap="roleAndUsersMap2" parameterType="int">
       select r.*,u.uid,u.uname,u.uphone,u.uemail,u.create_time as ctime,
        u.update_time as utime from sysrole r,sysuser u where r.rid=u.rid and r.rid =#{rid}
    </select>

4.动态sql语句(重要)

在映射文件中进行sql语句拼接.

if/where标签
  • if:用来做条件判断
  • where:用来生成where关键字.并忽略紧跟其后的and或or如果if都为null或者’'那么这个where标签不会添加where
<select id="selectUsers" parameterType="sysuser" resultType="sysuser">
    select uid,uname,uphone,upwd,uemail,create_time,update_time from sysuser
    <where>
        <if test="uname!=null and uname!=''">
            and  uname=#{uname}
        </if>
        <if test="uphone!=null and uphone!=''">
            and uphone=#{uphone}
        </if>
        <if test="uemail!=null and uemail!=''">
            and  uemail=#{uemail}
        </if>
       	 <!--  如果查询的字段是Intger类型则不用写and uphone!=''
         <if test="uphone!=null">
               uphone=#{uphone}
         </if>-->
    </where>
    order by update_time desc
</select>
set标签
  • set:用来生成set关键字,update语法.并忽略最后的逗号,
<update id="updateUser" parameterType="sysuser">
    update sysuser
    <set>
        /*修改不用写uname!=''因为可能前端想故意把字段写为''空*/
        <if test="uname!=null">
            uname=#{uname},
        </if>
        <if test="uphone!=null">
            uphone=#{uphone},
        </if>
    </set>
    where uid=#{uid}
</update>
foreach标签
  • foreach:用来做批量删除
		int delUsers(List<Integer> uids);批量删除,
    =========================================================
方法一   | List<Integer> uids	:mybatis底层把List封装成map,默认key是<list>
方法二   | Integer[] uids		:mybatis底层把数组封装成map,默认key是<array>
方法三   | 用@Param("uids")注解自定义key     

collection – 传递参数类型list/array/自定义key index – 循环索引

item – 集合中的元素 open –以什么开始; close – 以什么结束

<delete id="delUsers" parameterType="map">
    DELETE FROM sysuser WHERE uid in 
    <foreach collection="list" open="(" close=")" item="uid_item" separator=",">
        #{uid_item}
    </foreach>
</delete>
  • 批量增加
 int addUsers(@Param("users") Sysuser[] users);
<insert id="addUsers" parameterType="map">
    insert into sysuser(uname,uphone) values
    <foreach collection="users" separator="," item="user">//没有开始和关闭,自己写
        (#{user.uname},#{user.uphone})
    </foreach>
</insert>
choose-when-otherwis标签
  • choose-when-otherwise:单条件查询,没用.

只会有一个when条件成立如果没有一个when条件成立那么会执行otherwise标签内容

<select id="selectUsers2" parameterType="sysuser" resultType="sysuser">
    select uid,uname,uphone,upwd,uemail,create_time,update_time from sysuser
    <where>
        <choose>
            <when test="uname!=null and uname!=''">
                and  uname=#{uname}
            </when>
            <when test="uphone!=null and uphone!=''">
                and uphone=#{uphone}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </where>
    order by update_time desc
</select>

5.mybatis的延迟加载,不重要

mybatis中的延迟加载仅在有二次查询的场景下生效.

延迟加载目的:减少无效的数据库查询操作,提高响应的效率.

延迟加载:分页,树形结构数据,前端图片的延迟加载

开启延迟加载时需要配置的setting

<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--启用延迟加载-->
<setting name="lazyLoadingEnabled" value="true"></setting>
<!--消极加载,只有当调用二级查询的字段时才加载-->
<setting name="aggressiveLazyLoading" value="false"></setting>
<!-- value值从equals,clone,hashCode,toString中选取如果以上些行为均不想触发则写上空格-->
<setting name="lazyLoadTriggerMethods" value=""></setting>

6.mybatis缓存,不重要

cache:减少数据库的重复查询操作.基于内存把第一次查询的结果保存的缓存对象中,当后续查询时,先查询缓存,缓存中有则返回;缓存中没有则查询数据库,并把查询结果放缓存.

mybatis的缓存分为两级:

session级别缓存:默认开启.在同一个session会话中发起相同的查询.

factory级别缓存:默认未开启.可以做到不同会话之间共享缓存数据.

开启factory二级缓存的步骤

  1. 在配置文件中添加settings
<setting name="cacheEnabled" value="true"></setting>
  1. 在对应的映射文件中做缓存策略配置
<!--缓存策略,只对当前namespace下的所有查询全部生效,
可以在用户查询概率较少的select标签中加useCache="false"禁用二级缓存,
可以在update,delete中使用flushCache="true"强制清空缓存--> 
<cache
  eviction="FIFO"					FIFO先进先出策略|LRU最近最少使用
  flushInterval="60000"				60秒清楚所有缓存
  size="512"						最大保存记录条数
  readOnly="true"/>					只读

猜你喜欢

转载自blog.csdn.net/weixin_45948874/article/details/114791013