首页 技术 正文
技术 2022年11月16日
0 收藏 393 点赞 2,565 浏览 7782 个字

8.1动态SQL中的元素

第8章 动态SQL

8.2<if>元素

举例,在映射文件中:

  <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer where 1=1
<if test="username !=null and username !=''">
<!-- and username like concat('%',#{username},'%') -->
and username like '%${username}%'
</if> <if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</select>

test属性多用于判断,判断真假,大部分情况都是用作非空判断。有时候也需要判断字符串、数字和枚举等,如果传入的查询条件非空就进行动态SQL组装。

大白话:此时的作用,就是,如果username不空 并且 不为空值。(一个是空,没有地址,也没有值;另一个是有地址,也有值,但是值是空),u符合条件就拼接and username like ‘%${username}%’这条语句,jobs同理。

符合if条件拼起来的语句就是

select * from t_customer where 1=1 and username like ‘%${username}%’ and jobs= #{jobs}

‘%${username}%’:%表示通配符,可以表示无限个字符,0也可以,这里表示只要有包含username的值就会被查出来,username的值会在对象customer被创建出来后设置。

在测试方法中:

/**
* 根据客户姓名和职业组合条件查询客户信息列表
*/
@Test
public void findCustomerByNameAndJobsTest(){ // 通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession(); // 创建Customer对象,封装需要组合查询的条件
Customer customer = new Customer();
customer.setUsername("jack");
customer.setJobs("teacher"); // 执行SqlSession的查询方法,返回结果集
List<Customer> customers = session.selectList("com.itheima.mapper"
+ ".CustomerMapper.findCustomerByNameAndJobs",customer); // 输出查询结果信息
for (Customer customer2 : customers) {
// 打印输出结果
System.out.println(customer2);
} // 关闭SqlSession
session.close();
}

大白话:创建对象customer,然后对它设值,表示要在表中查询像这个对象的数据项,这里表示要查找 username中有包含有“jack”(无论在哪个位置)并且jobs的值是“teacher”的数据项。把java语句映射成SQL语句去数据库里查询,把查询得到的结果放在Customer列表中,然后输出。在关闭执行器。

专业术语:使用Customer对象封装了用户名为jack且职业为teacher的查询条件,并通过SqlSession对象的selectList()方法执行多条件组合的查询操作。

如果把两条set语句注释掉,再次执行执行的SQL语句是:select * from t_customer where 1=1,所有数据项都会被查出来。这里表明:当未传递任何参数时,程序会将数据表中所有的数据查出,这就是<if>元素的使用。

如果在映射文件中去掉1=1这个真值,则SQL语句变成:select * from t_customer where and username like ‘%jack%’ and jobs= ?

显然where后直接跟and会有语法错误。1=1的作用是避免where后面第一个词是and或者or之类的关键词,导致报错。

8.3 <choose>、<when>、<otherwise>元素

这些类似于java语句中的switch、case和default语句。

举例,在映射文件中:

    <!--<choose>(<when>、<otherwise>)元素使用 -->
<select id="findCustomerByNameOrJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer where 1=1
<choose>
<when test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</when>
<when test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</select>

大白话:在<choose>元素中,有好多好多个<when>元素,如果第一个<when>元素的test为真,只动态组装第一个<when>元素里的SQL片段,否则看第二个<when>元素,如果第二个为真,则只拼接第二个<when>元素里的SQL片段,以此类推。当前面所有的<when>元素中的test都不为真时,只组装<otherwise>元素内的SQL片段。相当于switch和case、default。

测试方法:

/**
* 根据客户姓名或职业查询客户信息列表
*/
@Test
public void findCustomerByNameOrJobsTest(){
// 通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession();
// 创建Customer对象,封装需要组合查询的条件
Customer customer = new Customer();
customer.setUsername("jack");
customer.setJobs("teacher");
// 执行SqlSession的查询方法,返回结果集
List<Customer> customers = session.selectList("com.itheima.mapper"
+ ".CustomerMapper.findCustomerByNameOrJobs",customer);
// 输出查询结果信息
for (Customer customer2 : customers) {
// 打印输出结果
System.out.println(customer2);
}
// 关闭SqlSession
session.close();
}

运行的SQL语句:select * from t_customer where 1=1 and username like concat(‘%’,?, ‘%’)

如果只注释掉customer.setUsername(“jack”)语句则运行的SQL语句:select * from t_customer where 1=1 and jobs= ?

如果只注释掉customer.setJobs(“teacher”)语句则运行的SQL语句:select * from t_customer where 1=1 and username like concat(‘%’,?, ‘%’)

如果都注释掉,则运行的SQL语句:select * from t_customer where 1=1 and phone is not null

concat起连接作用,实现模糊查询,这里效果等同’%${username}%’。

8.4 <where>、<trim>元素

又想防止语法错误又不想写1=1。

举例1,在映射文件中:

<!-- <where>元素 没有1=1的,用where元素代替  -->        <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer
<where>
<if test="username !=null and username !=''">
and username like concat('%',#{username},'%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</where>
</select>

不仅不要1=1,连where都换成元素了。<where>元素会自动判断组合条件下拼接的SQL语句,只有<where>元素内的条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;即使where之后的内容有多余的and或者or都会自动删除。

举例2,在映射文件中:通过<trim>元素来定制需要的功能

  <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
select * from t_customer
<trim prefix="where" prefixOverrides="and">
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</trim>
</select>

专业话:<trim>元素的作用是除去一些特殊的字符串,他的prefix属性代表的是语句的前缀(这里使用where来连接后面的SQL片段),而prefixOverrides属性代表的是需要除去的那些特殊字符串(这里定义除去SQL中的and),上面的写法和使用<where>元素基本是等效的。

8.5<set>元素

set是设置的意思,不是集合的意思

在Hibernate中,想要更新某个对象,就需要发送所有的字段给持久化对象,这种想更新的每一条数据都要将其所有的属性都更新一遍的方法,其执行效率非常差的。为此,在MyBatis中可以使用动态SQL中的<set>元素进行处理:使用<set>和<if>元素对username和jobs进行更新判断,并动态组装SQL。这样就只需要传入想要更新的字段即可。

举例,在映射文件中:

    <update id="updateCustomer" parameterType="com.itheima.po.Customer">
update t_customer
<set>
<if test="username !=null and username !=''">
username=#{username},
</if>
<if test="jobs !=null and jobs !=''">
jobs=#{jobs},
</if>
<if test="phone !=null and phone !=''">
phone=#{phone},
</if>
</set>
where id=#{id}<!-- id=#{id}-->
</update>

测试方法:

/**
* 更新客户
*/
@Test
public void updateCustomerTest() {
// 获取SqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 创建Customer对象,并向对象中添加数据
Customer customer = new Customer();
customer.setId(3);
customer.setPhone("13311111234");
customer.setUsername("bossli");
// 执行SqlSession的更新方法,返回的是SQL语句影响的行数
int rows = sqlSession.update("com.itheima.mapper"
+ ".CustomerMapper.updateCustomer", customer);
// 通过返回结果判断更新操作是否执行成功
if(rows > 0){
System.out.println("您成功修改了"+rows+"条数据!");
}else{
System.out.println("执行修改操作失败!!!");
}
// 提交事务
sqlSession.commit();
// 关闭SqlSession
sqlSession.close();
}

运行结果:

第8章 动态SQL

如果映射文件中“where id=#”改成“where 1=1”则修改全部数据。

8.6 <foreach>元素

   <!--<foreach>元素使用 -->
<select id="findCustomerByIds" parameterType="List"
resultType="com.itheima.po.Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="list" open="("
separator="," close=")">
#{id}
</foreach>
</select>

item:配置的是循环中当前的元素。

index:配置的是当前元素在集合的位置下标。

collection:配置的是list传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名等。

open和close:配置的是以什么符号将这些集合元素包装起来。

separator:配置的是各个元素的间隔符。

测试方法:

/**
* 根据客户编号批量查询客户信息
*/
@Test
public void findCustomerByIdsTest(){
// 获取SqlSession
SqlSession session = MybatisUtils.getSession(); // 创建List集合,封装查询id
List<Integer> ids=new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3); //等于下面
// for(int i=1;i<=3;i++)
// ids.add(i); // 执行SqlSession的查询方法,返回结果集
List<Customer> customers = session.selectList("com.itheima.mapper"
+ ".CustomerMapper.findCustomerByIds", ids); // 输出查询结果信息
for (Customer customer : customers) {
System.out.println(customer);
} // 关闭SqlSession
session.close();
}

运行结果:

第8章 动态SQL

在使用<foreach>时最关键也是最容易出错的就是collection属性,该属性是必须指定的(按实际情况进行配置),而且在不同情况下,该属性的值是不一样的。主要有以下3种情况:

a)、如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection)。

b)、如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。

c)、如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。

8.7 <bind>元素

SQL语句:select * from t_customer where username like ‘%${value}%’

不妥之处:

a)、如果使用“${}”进行字符串拼接,则无法防止SQL注入问题;

b)、如果改用concat函数进行拼接,则只针对MySQL数据库有效;

c)、如果改用“||”进行字符串拼接,则只针对Oracle数据库有效。

总之:能用#就别用$

例如,在映射文件中:

<!--<bind>元素的使用:根据客户名模糊查询客户信息 -->
<select id="findCustomerByName" parameterType="com.itheima.po.Customer"
resultType="com.itheima.po.Customer">
<!--_parameter.getUsername()也可直接写成传入的字段属性名,即username -->
<bind name="pattern_username" value="'%'+_parameter.getUsername()+'%'" />
select * from t_customer
where
username like #{pattern_username}
</select>

专业话:<bind>元素定义了一个name为patter_username的变量,<bind>元素中value的属性值就是拼接的查询字符串,其中_parameter.getUsername()表示传递进来的参数(也可以直接写成对应的参数变量名,如username)。

其中_parameter这个东西是固定的。

测试方法:

/**
* bind元素的使用:根据客户名模糊查询客户信息
*/
@Test
public void findCustomerByNameTest(){ // 通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession(); // 创建Customer对象,封装查询的条件
Customer customer =new Customer();
customer.setUsername("j"); // 执行sqlSession的查询方法,返回结果集
List<Customer> customers = session.selectList("com.itheima.mapper"
+ ".CustomerMapper.findCustomerByName", customer);
// 输出查询结果信息
for (Customer customer2 : customers) {
System.out.println(customer2);
}
// 关闭SqlSession
session.close();
}

测试结果:

第8章 动态SQL

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,000
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,512
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,358
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,141
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,771
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,849