Java第三十七天,Mybatis框架系列,Mybatis 的动态 SQL 语句
一、<if>标签
1.格式
1=1 永真, 1<>1 永假
<select id="查询方法名" resultType="返回类型" parameterType="参数类型">
select * from user
<!---->
where 1=1
<!--if 标签中 test 属性中写的是对象的属性名-->
<if test="判断条件">
and 附加条件(后面有多少个条件就写多少次 and 语句)
</if>
</select>
举例1
<!--<if>标签的 test 属性中写的是传入对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法-->
<!--if test 标签中能识别的变量是传入的变量;其余区域如果想要访问传入的变量需要使用 ${} 或者 #{};否则一律视为数据库表中的字段-->
<!--功能:如果用户输入不为空,则根据输入模糊查询,如果为空,则模糊查询 username 字段中含有 1 的数据-->
<select id="findUsersByCon" resultType="entil.User" parameterType="java.lang.String">
select * from user
where 1 = 1
<if test="value != null and value != '' ">
and username like '%${value}%'
</if>
<if test="value == null or value == '' ">
and username like '%1%'
</if>
</select>
举例2
<!--<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法-->
<!--if test 标签中能识别的变量是传入的变量;其余区域如果想要访问传入的变量需要使用 ${} 或者 #{};否则一律视为数据库表中的字段-->
<!--功能:如果传入对象的 username 不为空,则查询模糊 username 为1的元祖;如果传入的 password 不为空则查询数据库中 password 字段和传入对象的 password 属性相同的元祖;并对结果进行与操作-->
<select id="findUsersByCon" resultType="entil.User" parameterType="entil.User">
select * from user
where 1 = 1
<!--注意,下面一行的 username 为传入参数的属性值-->
<if test="username != '' and username != null">
<!--注意,下面一行的第一个 username 为数据库中的字段标识,第二个 username(被${}包住)为传入变量的属性值-->
and username like '%${username}%'
</if>
<!--同理;注意多个同级的 if 标签 “并联“ 时,会对所有的查询结果进行 与 操作-->
<if test="password != '' or password != null">
and password = #{password}
</if>
</select>
2.为什么要 where 1 = 1
用于应用程序根据用户选择项的不同拼凑where条件时用的
例如:查询用户的信息,where默认为1=1,这样用户即使不选择任何条件,sql查询也不会出错
如果不用1=1的话,每加一个条件,都要判断前面有没有where 条件,如果没有就要先写where ,再追加and语句,如果有就直接追加and语句,因此此时用1=1可以简化了应用程序的复杂度
优秀博文推荐:
https://blog.csdn.net/qq_36654606/article/details/86627720
二、<where>标签
1.格式
<select id="方法名" resultType="返回结果类型" parameterType="传入对象类型">
<include refid="引用的 SQL 语句段 的ID"></include>
<where>
<if test="">
and
</if>
......
</where>
</select>
2.出现原因
where 标签的出现是为了替换掉 where 1 = 1 这段代码
3.如何使用
(1)将 where 1 = 1 删除
(2)将所有的 if 语句放在 where 标签中
举例:
<select id="findUsersByCon" resultType="entil.User" parameterType="entil.User">
select * from user
<where>
<!--注意,下面一行的 username 为传入参数的属性值-->
<if test="username != '' and username != null">
<!--注意,下面一行的第一个 username 为数据库中的字段标识,第二个 username(被${}包住)为传入变量的属性值-->
and username like '%${username}%'
</if>
<!--同理;注意多个同级的 if 标签 “并联“ 时,会对所有的查询结果进行 与 操作-->
<if test="password != '' or password != null">
and password = #{password}
</if>
</where>
</select>
三、foreach 标签
1.使用场景
当查询条件为一个集合时需要用到
2.格式
<foreach collection="要遍历的集合" open="数据库中的某属性 in ( " close=")" item="自定义标识"separator=",">
#{自定义标识(必须与上面一致)}
</foreach>
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
3.举例
(1)实体类
package entil;
import java.io.Serializable;
public class User implements Serializable {
private Integer officeid;
private String username;
private String password;
public Integer getOfficeid() {
return officeid;
}
public void setOfficeid(Integer officeid) {
this.officeid = officeid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"officeid=" + officeid +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
(2)查询条件类(包含查询条件集合综合类)
package dao;
import java.io.Serializable;
import java.util.List;
public class QueryVo implements Serializable {
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
(3)Dao/Mapper文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.IUserDao">
<!-- collection:代表要遍历的集合元素,注意编写时不要写#{}-->
<!-- open:代表语句的开始部分-->
<!-- close:代表结束部分-->
<!-- item:代表遍历集合的每个元素,生成的变量名-->
<!-- sperator:代表分隔符-->
<!-- 这段代码的意思是遍历指定的表,并将表中 officeid 字段被包含在传入变量的属性 ids(集合) 的所有元祖查询并返回-->
<select id="findUsersByIds" resultType="entil.User" parameterType="dao.QueryVo">
select * from user
<where>
<!--集合类型判断是否为空时不能 ?=='';这样会导致集合和字符串比较,会报错-->
<!--test 里边的变量为传入变量的属性;即 ids 为 QueryVo 的属性-->
<if test="ids != null and ids.size() > 0">
<!--collection 用于指定要遍历的 集合对象;office 为数据库中表的字段名称-->
<!--下面这句话的意思是遍历指定的集合,并将遍历的结果放到 开始和结束(open和close代表的两个括号的中间)-->
<foreach collection="ids" open="and officeid in (" close=")" item="id" separator=",">
<!--取决于 item 定义的属性名-->
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
(4)持久层接口类
package dao;
import entil.User;
import java.util.List;
public interface IUserDao {
public abstract List<User> findUsersByIds(QueryVo queryVo);
}
(5)持久层接口实现类
package dao;
import entil.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserDaoImpl implements IUserDao{
private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;
public UserDaoImpl(){
try {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
} catch (IOException e) {
e.printStackTrace();
}
//创建工厂
//创建工厂时,mybatis使用了构建者模式,即找包工队盖房子,而不是自己亲自处理一系列问题
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(IUserDao.class);
}
// java中的析构函数
@Override
public void finalize(){
sqlSession.close();
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public List<User> findUsersByIds(QueryVo queryVo) {
return userDao.findUsersByIds(queryVo);
}
}
(6)入口类
import dao.IUserDao;
import dao.QueryVo;
import dao.UserDaoImpl;
import entil.User;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception{
IUserDao userDao = new UserDaoImpl();
QueryVo queryVo = new QueryVo();
List<Integer> list = new ArrayList<Integer>();
list.add(6);
list.add(111);
queryVo.setIds(list);
List<User> all = userDao.findUsersByIds(queryVo);
for(User userTemp : all){
System.out.println(userTemp.toString());
}
}
}
四、引用代码片段 ===> <include refid=""></include>
1.作用
减少代码冗余度;提高可读性
2.使用
<!-- 抽取重复的语句代码片段 -->
<sql id="定义好的代码段标识ID">
数据库语句
</sql>
<!-- 调用语句-->
<select id="" resultType="">
<include refid="定义好的代码段标识"></include>
</select>
3.举例
<!--表名 -->
<sql id="tableName">
User
</sql>
<!-- 字段 -->
<sql id="Field">
INDEX_CODE,
INDEX_NAME,
INDEX_CAL_TYPE,
INDEX_DATA_TYPE,
UUID
</sql>
<!-- 字段值 -->
<sql id="FieldValue">
#{indexCode},
#{indexName},
#{indexCalType},
#{indexDataType},
#{uuid}
</sql>
<!-- 通过ID获取数据 -->
<select id="findByIndexId" parameterType="String" resultType="User">
select
<include refid="Field"></include>
from
<include refid="tableName"></include>
where
UUID = #{indexId}
</select>