在业务比较复杂的情况下,我们通常需要去拼接SQL语句来完成相关操作,这样出错率很高,不过,MyBatis有一个非常方便且强大的功能就是动态SQL,使用动态SQL,可以摆脱手动拼SQL的痛苦,接下来我们就一起来学习如何使用MyBatis动态SQL。
先来看看我们用的student表:
目录结构:
Student实体类:
/**
* @ClassName Student
* @Description
* @Author lzq
* @Date 2019/7/26 13:53
* @Version 1.0
**/
public class Student {
private int SID;
private String Sname;
private String Ssex;
private int Age;
public int getSID() {
return SID;
}
public void setSID(int SID) {
this.SID = SID;
}
public String getSname() {
return Sname;
}
public void setSname(String sname) {
Sname = sname;
}
public String getSsex() {
return Ssex;
}
public void setSsex(String ssex) {
Ssex = ssex;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
Age = age;
}
@Override
public String toString() {
return "[id"+SID+" 名字"+Sname+" 性别"+Ssex+" 年龄"+Age+"]";
}
}
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--数据源配置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
StudentMapper接口:
public interface StudentMapper {
public Student getStudent(Student student);
}
StudentMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tulun.dao.StudentMapper">
<select id="getStudent" parameterType="tulun.bean.Student" resultType="tulun.bean.Student">
select * from Student where SID = #{SID} and Sname = #{Sname}
and Ssex = #{Ssex} and Age = #{Age}
</select>
</mapper>
测试类:
/**
* @ClassName Test
* @Description
* @Author lzq
* @Date 2019/7/26 13:53
* @Version 1.0
**/
public class Test {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
//读取配置文件
InputStream asStream = Resources.getResourceAsStream(resource);
//创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);
//创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过动态代理产生StudentMapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//查询对象
Student student1 = new Student();
student1.setSID(1);
student1.setSsex("nan");
student1.setSname("lzq");
student1.setAge(21);
mapper.getStudent(student1)
}
}
运行结果:
很显然,参数student的属性完全匹配数据库第一条记录,是可以查询出结果的。
现在对代码进行修改,去掉student的ssex属性赋值操作,通过id,sname,age三个字段去匹配,理想的结果是同样可以查询出数据库的第一条记录。
测试类:
/**
* @ClassName Test
* @Description
* @Author lzq
* @Date 2019/7/26 13:53
* @Version 1.0
**/
public class Test {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
//读取配置文件
InputStream asStream = Resources.getResourceAsStream(resource);
//创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);
//创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过动态代理产生StudentMapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//查询对象
Student student1 = new Student();
student1.setSID(1);
student1.setSname("lzq");
student1.setAge(21);
mapper.getStudent(student1)
}
}
但是结果为0,什么原因呢?因为SQL语句where条件使用的是and关键字进行连接,所有条件必须同时满足,我们可以看到此时的SQL语句:
"select * from Student where SID = 1 and Sname = lzq and Ssex = null and Age = 21
"
显然这条SQL语句是查询不出任何结果的。
现在针对这种情况进行优化,判断Student对象,如果ssex属性值不为null,则SQL语句添加ssex的判断,如果password属性为null,则不添加。
我们可以使用动态SQL来完成上述操作。
使用if标签:
StudentMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tulun.dao.StudentMapper">
<!-- if标签 -->
<select id="getStudent" resultType="tulun.bean.Student" parameterType="tulun.bean.Student">
select * from Student where 1=1
<if test="SID != 0">
and SID = #{SID}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
<if test="Sname != null">
and Sname = #{Sname}
</if>
<if test="Age != 0">
and Age = #{Age};
</if>
</select>
</mapper>
还是刚刚用的测试代码:
在if标签中的SQL语句的where后面添加1=1的原因是:
如果我们给第一个字段赋值:
那么SQL语句如下:
"select * from Student where SID = 1 and Sname = lzq and Ssex = null and Age = 21
"
要是不给第一个字段赋值呢?"select * from Student where and Sname = lzq and Ssex = null and Age = 21
"
这样会报错的,那么我们如何处理这个呢,就是像本文一样,加个1=1这个条件,或者使用where标签。
where标签:
这个一般是和if标签一起使用的:
StudentMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tulun.dao.StudentMapper">
<!-- where标签 -->
<select id="getStudent" resultType="tulun.bean.Student" parameterType="tulun.bean.Student">
select * from Student
<where>
<if test="SID != 0">
and SID = #{SID}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
<if test="Sname != null">
and Sname = #{Sname}
</if>
<if test="Age != 0">
and Age = #{Age};
</if>
</where>
</select>
</mapper>
效果就是,如果条件一个都不满足,则不拼接where条件;如果有一个或者是多个表达式成立,where会直接拼接在SQL上,并且紧随where的表达式的and会被忽略掉;
运行结果都差不多,不展示了,
还可以进行批量操作,比如批量查询操作:
StudentMapper接口:
public interface StudentMapper {
public List<Student> batchQueryStudent(List<Integer> list);
public Student getStudent(Student student);
}
StudentMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tulun.dao.StudentMapper">
<!-- where标签 -->
<select id="getStudent" resultType="tulun.bean.Student" parameterType="tulun.bean.Student">
select * from Student
<where>
<if test="SID != 0">
and SID = #{SID}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
<if test="Sname != null">
and Sname = #{Sname}
</if>
<if test="Age != 0">
and Age = #{Age};
</if>
</where>
</select>
<!--批量操作 -->
<select id="batchQueryStudent" resultType="tulun.bean.Student" parameterType="tulun.bean.Student">
select * from Student where SID in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
</mapper>
测试代码:
public class Test {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
//读取配置文件
InputStream asStream = Resources.getResourceAsStream(resource);
//创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(asStream);
//创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过动态代理产生StudentMapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Student> list1 = mapper.batchQueryStudent(list);
System.out.println(list1);
}
}
顺便说一下,在配置文件里面,SQL语句的参数可以是#{}
还可以是${}
,这两者有什么区呢?
#{}
相当于JDBC里面的PreparedStatement ;
先编译,编译没问题在拿这个编译的结果去执行:
${}
相当于JDBC里面的Statement
直接拿,然后编译执行;
所以相比之下,#{}效率更高,并且不存在SQL注入问题,比较安全;