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形式 |
---|---|
< | < |
<= | <= |
> | > |
>= | >= |
& | & |
’ | ' |
" | " |
like通用格式
and a.cname like '%'||#{po.keyword}||'%'