【框架专题】工具组件——Mybastis应用——技术应用手册

本文详述MyBatis框架中SQL参数的传递机制,包括单参数、多参数、动态SQL参数处理及预读绑定参数的方法。同时,介绍了SQL返回结果的封装策略,如简单实体、级联实体及存储过程的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mybastis——SQL参数访问机理

单参数

参数类型SQL形式解释
基本类型:数值(Integer id)#{id}参数名就是key
对象参数(User)#{uid},#{username}get参数名获取
集合参数(List list)#{list【0】}参数名就是key值,可以访问下标

多参数

参数类型SQL形式解释
多参无注解(username,password)#{parm1},#{parm2}封装一个map集合!其中key是parm1……parmN
多参有注解(@Param username,@Param password)#{username},#{password}封装一个map集合!其中key是注解值

Mybastis——SQL参数注入操作

动态拼接sql参数

(1)IF标签

决定了标签内的sql是否会被渲染
【1】可以直接利用参数名访问参数值
【2】可以调用数据处理类的api,比如email.trim()
【3】特殊字符需要转义,比如&=&空值=&quto;

<if test="po.keyword !=null and   po.keyword != ''">

问题的出现

   下面的sql语句如何 id是null,username不是null则拼多了一个and导致sql报错
   <select id="getChildRole" resultMap="BaseRoleMap">
        select * from t_user 
	     where 
	     <if test="id!=null">id=#{id}</if>
         <if test="username!=null">and username=#{username}</if>
         <if test="idnum!=null">and idnum=#{idNum}</if>
    </select>

(2)where标签——select语句

需要约定and放在前面,自动添加where关键字、删除(最前面的and)

<where>
			<if test="id!=null">and id=#{id}</if>
			<if test="username!=null">and username=#{username}</if>
</where>

(3)set标签——update语句

需要约定逗号放在最后面,自动添加set关键字、删除(最后的逗号)

<set>
		 	<if test="phone!=null">phone=#{phone},</if>
		 	<if test="email!=null">email=#{email},</if>
		 	<if test="gender!=null">gender=#{gender},</if>
</set>

(4)trim标签——任意语句

前缀、后缀、单前多余匹配删除、单后多余匹配删除
【1】Prefix:整体前缀添加……,一般是where或者set!
【2】suffix:整体后缀添加…… 一般不用,看实际
【3】prefixOverrides:去除整体中前缀的……字符
【4】suffixOverrides:去除整体标签中后缀的……字符

<trim prefix="where" suffix="" prefixOverrides="and" suffixOverrides="and">
			<if test="id!=null">and id=#{id} and</if>
			<if test="username!=null">and username=#{username} and</if>
</trim>

(5)choose标签拼接

if else类型

<where>
		<choose>
				<when test="id!=null">id=#{id}</when>
				<when test="username!=null">and username=#username</when>
				<otherwise>fuckyou</otherwise>
		</choose>
</where>

循环拼接sql参数

通常用于批量插入数据,遍历外部的数组

  <insert id="batchInsertCarBaseCalendar">
       insert into car_base_calendar 		
    (id,corp_id,date,is_holiday,day_of_week,day_desc,create_by,create_time,update_by,update_time,year)
        values
       <foreach collection="cals" item="item" separator=",">
          (null,
          #{item.corpId,jdbcType=BIGINT},
          #{item.date,jdbcType=VARCHAR},
          #{item.isHoliday,jdbcType=INTEGER},
          #{item.dayOfWeek,jdbcType=INTEGER},
          #{item.dayDesc,jdbcType=VARCHAR},
          #{item.createBy,jdbcType=VARCHAR},
          #{item.createTime,jdbcType=TIMESTAMP},
          #{item.updateBy,jdbcType=VARCHAR},
          #{item.updateTime,jdbcType=TIMESTAMP},
          #{item.year,jdbcType=VARCHAR}
           )
       </foreach>
 </insert>

预读绑定sql参数

为了解决#前后不能拼字符串,则$又有sql注入风险的情况
value=取出参数值并做处理
name=把这个处理值封装进这里,然后再sql中就可以用#访问了!

<select id="">
    <bind name="_lastname" value="'%'+lastname+'%'"/>
    select
    *
    from
    user
    where
    last_name like #{_lastname}
</select>

结构剖析

<foreach collection="ids"  参数的key
			item="id"      每遍历一次的变量名
			index="p"      元素的下标,map则是key
			open="(" 	   头拼接
			close=")" 	   尾拼接
			separator=","  参数分隔符
>
			#{emp.id}
</foreach>

复用sql参数

利用refid将某一段sql拿出来,然后拼接到语句中
参数解释:refid=指定复用sql的id标识

调用本模块的复用块

 <sql id="Base_Column_List">
        id,
        create_by,
        create_date,
        update_by,
        update_date,
        user_id,
        role_id,
        tenant_id,
        sys_id
 </sql>
 <select id="queryByName" parameterType="java.lang.String" resultMap="BaseResultMap">
      select
        <include refid="Base_Column_List" />
        from t_user t
        where t.user_status in ('0','1')
            and  t.user_name = #{name}
 </select>

调用其他模块的复用块

<include refid="com.ypzx.ypzxbis.common.Mapper.commonStudentPool"/>

调用有参复用块

(1):name=指定参数的名,在sql中条件表达式或者数据表达式可以都可以用#、$访问
(2):value=传过去的参数值,可以直接访问我们的值;表达式中可以直接访问,标签体中就必须用# $

<sql id="insertcolumn">
    <if test="_databaseId=='oracle'">id,username,password,${one}</if>
    <if test="_databaseId='mysql'">id,username,password,${one}</if>
</sql>
<insert id="fcuk">
    insert into emp(
    <include refid="insertcolumn">
        <property name="one" value="shit"/>
    </include>
    )
</insert>

Mybastis——SQL返回封装操作

简单实体封装

【单行-哈希封装】——————Map<String, Object> getEmpByIdReturnMap(Integer id);
<select id="getEmpByIdReturnMap" resultType="map">				
   select * from tbl_employee where id=#{id}
</select>
【单行-实体封装】——————Employee getEmpByMap(Map<String, Object> map);
<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee">		
   select * from ${tableName} where id=${id} and last_name=#{lastName}
</select>
【多行-数组封装】——————List<Employee> getEmpsByLastNameLike(String lastName);
<select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee">
   select * from tbl_employee where last_name like #{lastName}
</select>

级联实体封装

,一般来讲我们都不会涉及到resultMap,大部分都通过VO平行扩展解决,但是涉及到嵌套的数据查询的时候,我们要用resultMap帮我们去做子查询并封装到实体类中,不过这种查询有点耗费性能大部分都通过java匹配解决

常见场景——嵌套VO对象
(0)对象情况

一般不会这样,建议用平行VO显示,一般只是为了不想多冗余一个业务型的外部VO

public class Employee {
    private String lastName;
    private String gender;
    private Department did;
}
public class Department {
    private String departmentName;
}

(1)对象类型.访问赋值法

左边:直接访问字段
右边:利用级联对象引用.属性名进行入位;

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
   <id column="id" property="id"/>
   <result column="last_name" property="lastName"/>
   <result column="gender" property="gender"/>
   <result column="did" property="dept.id"/>
   <result column="dept_name" property="dept.departmentName"/>
</resultMap>

(2)对象类型.嵌套赋值法

左边:直接访问字段
右边:直接自己实体的属性名
优点:不用.了

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
   <id column="id" property="id"/>
   <result column="last_name" property="lastName"/>
   <result column="gender" property="gender"/>
   <association property="dept" javaType="com.atguigu.mybatis.bean.Department">
      <id column="did" property="id"/>
      <result column="dept_name" property="departmentName"/>
   </association>
</resultMap>

(3)鉴别器

取出gender作为case的value判断,成功的则将采用指定标签的策略!

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
   <id column="id" property="id"/>
   <result column="last_name" property="lastName"/>
   <result column="email" property="email"/>
   <result column="gender" property="gender"/>

   <discriminator javaType="string" column="gender">
      <case value="0" resultType="com.atguigu.mybatis.bean.Employee">
         <association property="dept" 
         select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
         column="d_id">
      	</association>
      </case>
      <case value="1" resultType="com.atguigu.mybatis.bean.Employee">
      	<id column="id" property="id"/>
      	<result column="last_name" property="lastName"/>
      	<result column="last_name" property="email"/>
      	<result column="gender" property="gender"/>
      </case>
   </discriminator>
</resultMap>

常见场景——嵌套子查询

具有树形上下级关系的数据查询

     <!--最外部查询-->
     <select id="getMenus" resultMap="BaseMenuMap">
      SELECT
	    m.id,
	    m.menu,
	    m.menu_code
	  FROM
	    t_role r
	    LEFT JOIN t_role_menu rm ON r.id = rm.role_id
	    LEFT JOIN t_menu m  ON  rm.menu_id = m.id where m.is_delete=0 and r.id=#{id}
    </select>
     <!--角色结果映射-->
     <resultMap id="BaseMenuMap" type="com.tencent.expense.model.entity.MenuEntity">
        <result column="id" property="id" />
        <result column="menu" property="menu" />
        <result column="parent_menu_id" property="parentMenuId" />
        <collection  
        			javaType="java.util.ArrayList"  					 集合的类型
                    ofType="com.tencent.expense.model.entity.MenuEntity" 集合的泛型
                    property="childMenuList" 							 该属性的名字
                    select="getChildMenu"								 该属性的数据源sql
                    column="id" 										 注入到上面sql的参数(从当前行内取出,并同名注入)
                    />
    </resultMap>
    <!--子查询-->
    <select id="getChildMenu" resultMap="BaseMenuMap">
        select
         m.menu,
	     m.menu_code,
	     m.parent_menu_id,
	     m.sys_id,
	     m.id
	     from t_menu m
	     where m.parent_menu_id=#{id}
    </select>

数据结构

public class MenuEntity extends SuperEntity {
    private static final long serialVersionUID = 1L;
    private String menu;
    private String menuCode;
    private String menuUrl;
    private Long parentMenuId;
    private String menuStatus;
    private String sysId;
    private List<MenuEntity> childMenuList;
}

Mybastis——SQL存储过程

<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
   {call hello_test(
      #{start,mode=IN,jdbcType=INTEGER},
      #{end,mode=IN,jdbcType=INTEGER},
      #{count,mode=OUT,jdbcType=INTEGER},
      #{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
   )}
</select>

Mybastis——SQL字符事项

参数类型SQL形式
<&lt;
<=&lt;=
>&gt;
>=&gt;=
&&amp;
&apos;
"&quot;

like通用格式

and a.cname like '%'||#{po.keyword}||'%'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值