一 OGNL表达式
OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式
语言,用来获取
和设置
Java对象的属性,它旨在提供一个更高的更抽象的层次
来对Java对象图进行导航。类似于我们的EL,SpEL等
OGNL表达式的基本单位
是"导航链",一般导航链由如下几个部分组成:
(1)属性名称(property)
(2)方法调用(method invoke)
(3)数组元素
所有的OGNL表达式都基于当前对
象的上下文
来完成求值运算,链的前面部分的结果将作为后面求值的上下文。例如:names[0].length()
。
常规用法
- 访问对象属性:
person.name
- 调用方法:
person.getName()
- 调用静态属性/方法:
@java.lang.Math@PI
;@java.util.UUID@randomUUID()
- 调用构造方法:
new com.atguigu.bean.Person(‘admin’).name
- 运算符:
+,-*,/,%
+逻辑运算符:in,not in,>,>=,<,<=,==,!=
注意:xml中特殊符号如”,>,<等这些都需要使用转义字符
表格用法
类型 | 伪属性 | 伪属性对应的 Java 方法 |
---|---|---|
List、 Set、 Map | size、 isEmpty | List/Set/Map.size(),List/Set/Map.isEmpty() |
List、 Set | iterator | List.iterator()、 Set.iterator() |
Map | keys、 values | Map.keySet()、 Map.values() |
Iterator | next、 hasNext | Iterator.next()、 Iterator.hasNext() |
二 if
<select id="findUserByIf" resultType="com.zyc.entity.User" parameterType="com.zyc.entity.User">
select id,username ,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex ,address from t_user
where 1 = 1
<if test="id != null">
and id = #{id}
</if>
<if test="username != null">
and username = #{username}
</if>
</select>
三 where
主要是用来简化
sql语句中where条件判断的,能智能的处理 and or
条件
mybatis使用where标签来将所有的查询条件包括在内(会自动加where关键
)。mybatis就会将where标签中拼装的sql,多出
来的and或者or去掉(where只会
去掉第一个多出来的and或者or)
总结 配合if
,剩下无用的 1=1
<select id="findUserByWhere" resultType="com.zyc.entity.User" parameterType="com.zyc.entity.User">
select id,username ,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex ,address from t_user
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="username != null">
and username = #{username}
</if>
</where>
</select>
四 trim
后面多出的and或者or where标签不能解决
- prefix="" 前缀:trim标签体中是整个字符串拼串 后的结果。prefix给拼串后的整个字符串加一个前缀
- prefixOverrides="" 前缀覆盖:
去掉
整个字符串前面多余
的字符 - suffix="" 后缀:suffix给拼串后的整个字符串加一个
后缀
- suffixOverrides="" 后缀覆盖:
去掉
整个字符串后面多余的字符
这些属性
里面可以写一些sql语句
或表达式
prefixoverride="AND |OR"
suffix=" where id = #{id} "
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
select * from t_blog
<trim prefix="where" prefixOverrides="and |or">
<if test="title != null">
title = #{title}
</if>
<if test="content != null">
and content = #{content}
</if>
<if test="owner != null">
or owner = #{owner}
</if>
</trim>
</select>
五 choose
相当于java 语言中的 switch ,与 jstl 中的choose 很类似
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 1 = 1
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="content != null">
and content = #{content}
</when>
<otherwise>
and owner = "owner1"
</otherwise>
</choose>
</select>
当when中有条件满足的时候,就会跳出choos
e,即所有的when和otherwise条件中,只有一个
会输出,当所有的我很条件都不满足的时候就输出otherwise
中的内容
六 set (主要用于更新时)
set元素主要是用在更新操作的时候,它的主要功能和where元素其实是差不多
的,主要是在包含的语句前
输出一个set
,然后如果包含的语句是以逗号结束
的话将会把该逗号忽略
(去掉),如果set包含的内容为空的话则会出错
。有了set元素我们就可以动态的更新
那些修改了的字段。
<!--public void updateEmp(Employee employee); -->
<update id="updateEmp">
<!-- Set标签的使用 -->
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
<!--
Trim:更新拼串
update tbl_employee
<trim prefix="set" suffixOverrides=",">
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id=#{id} -->
</update>
七 foreach
在实现 mybatis in 语句查询时特别有用
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。
(1)item
表示集合中每一个元素进行迭代时的别名
。
(2)index
索引。遍历list
的时候是index就是索引
,item就是当前值;遍历map
的时候index表示的就是map的key
,item就是map的值
(3)open
遍历出所有结果
拼接一个开始的字符
(4)separator
表示在每次进行迭代之间
以什么符号作为分隔符
。
(5)close
遍历出所有结果
拼接一个结束的字符
(6)collection
指定要遍历的集合:list类型的参数会特殊处理
封装在map中,map的key就叫list
在使用foreach的时候·最关键·的也是·最容易出错·的就是·collection属性·,该属性是·必须指定·的,但是在·不同情况下·,该属性的值是不一样的,主要有一下3种情况:
(1)如果传入的是单参数且参数类型是一个List的时候,collection属性值为list。对应上面的特殊处理
(2)如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array 也是mybatis处理的
(3)如果传入的参数是多个的时候,我们
就需要把它们封装
成一个Ma
p了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名
,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key
。
单参数List的类型
public List<User> dynamicForeachTest(List<Integer> ids)
<select id="dynamicForeachTest" resultType="com.mybatis.entity.User">
select * from t_user where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
数组类型的参数
<select id="dynamicForeach2Test" resultType="com.mybatis.entity.User">
select * from t_user where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
Map类型的参数
<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User">
select * from t_user where username like '%${username}%' and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
public List<User> dynamicForeach3Test(Map<String, Object> params);
调用demo
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(6);
Map map =new HashMap();
map.put("username", "小");
map.put("ids", ids);
List<User> userList = mapper.dynamicForeach3Test(map);
System.out.println("------------------------");
for (User user : userList){
System.out.println(user);
}
八 bind
bind标签的两个属性都是必选项
,name为绑定到上下文的变量名
,value为OGNL表达式
,创建一个bind标签后,就可以在下面直接使用了
。 使用bind拼接字符串不仅可以避免因更换数据库而修改SQL,也能预防SQL注入
<select id="selectSysUserByAdvancedCondition" resultType="com.artisan.mybatis.xml.domain.SysUser">
SELECT
a.id,
a.user_name userName,
a.user_password userPassword,
a.user_email userEmail,
a.user_info userInfo,
a.head_img headImg,
a.create_time createTime
FROM
sys_user a
<where>
<if test="userName != null and userName != '' ">
<bind name="userNameLike" value=" '%' + userName + '%' "/>
and user_name like #{userNameLike}
</if>
<if test="userEmail != null and userEmail != '' ">
and user_email = #{userEmail}
</if>
</where>
</select>
九 sql片段
抽取可重用
的sql片段。方便后面引用
- ·sql抽取·:·经·常将要查询的列名,或者插入用的·列名·抽取出来方便引用
-
include
来引用
已经抽取的sql: - include还可以
自定义一些property
,sql标签内部就能使用自定义的属性
include-property
:取值的正确
方式${prop}, #{不能
使用这种方式}
<sql id="insertColumn">
<if test="_databaseId=='oracle'">
employee_id,last_name,email
</if>
<if test="_databaseId=='mysql'">
last_name,email,gender,d_id
</if>
</sql>
十 批量保存
MySQL
两种方式
<!--public void addEmps(@Param("emps")List<Employee> emps); -->
<!--MySQL下批量保存:可以foreach遍历 mysql支持values(),(),()语法-->
<insert id="addEmps">
insert into tbl_employee(
<include refid="insertColumn"></include>
)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert>
<!-- 这种方式需要数据库连接属性allowMultiQueries=true;
这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
<insert id="addEmps">
<foreach collection="emps" item="emp" separator=";">
insert into tbl_employee(last_name,email,gender,d_id)
values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert>
Oracle
<!-- Oracle数据库批量保存:
Oracle不支持values(),(),()
Oracle支持的批量方式
1、多个insert放在begin - end里面
begin
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test_001','test_001@atguigu.com');
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test_002','test_002@atguigu.com');
end;
2、利用中间表:
insert into employees(employee_id,last_name,email)
select employees_seq.nextval,lastName,email from(
select 'test_a_01' lastName,'test_a_e01' email from dual
union
select 'test_a_02' lastName,'test_a_e02' email from dual
union
select 'test_a_03' lastName,'test_a_e03' email from dual
)
-->
<insert id="addEmps" databaseId="oracle">
<!-- oracle第一种批量方式 -->
<!-- <foreach collection="emps" item="emp" open="begin" close="end;">
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,#{emp.lastName},#{emp.email});
</foreach> -->
<!-- oracle第二种批量方式 -->
insert into employees(
<!-- 引用外部定义的sql -->
<include refid="insertColumn">
<property name="testColomn" value="abc"/>
</include>
)
<foreach collection="emps" item="emp" separator="union"
open="select employees_seq.nextval,lastName,email from("
close=")">
select #{emp.lastName} lastName,#{emp.email} email from dual
</foreach>
</insert>
十一 内置参数
不只是
方法传递过来的参数可以被用来判断,取值等操作
mybatis默认还有两个内置参数:
-
_parameter
:代表整个参数
单个参数:_parameter就是这个参数
多个参数:参数会被封装为一个map;_parameter就是代表
这个map
-
_databaseId
:如果配置了databaseIdProvider标签
(主配置文件中
)。
_databaseId就是代表当前数据库的别名oracle
<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
<bind name="_lastName" value="'%'+lastName+'%'"/>
<if test="_databaseId=='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
where last_name like #{lastName}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
<if test="_parameter!=null">
where last_name like #{_parameter.lastName}
</if>
</if>
</select>
参考
- Mybatis学习总结(五)——动态sql
- 尚硅谷mybatis教程资料
- MyBatis-15MyBatis动态SQL之【bind】