记录生活中的点点滴滴

0%

MyBatis学习总结

学校的考试也考的差不多了,就剩一个单片机了。昨天下午开始学习MyBatis,到现在差不多一天的时间,一遍看视频,一遍跟着敲一遍,再写一下博客。三步走战略,感觉还挺不错的!学到了不少东西,下面是自己肝的博客,主要得配置一些东西,感觉还是把这些记录下来,以后也能用得到。

首先我们要会建立一个maven工程,不会的小伙伴可以参考我以前写的这篇文章:maven配置使用,这个后面还介绍了Tomcat7的配置,接下来的MyBatis学习并不会用到它,所以看到3.2就行了,能建一个maven工程就可以了。

这篇博客总结的主要内容如下:

  • 了解软件的三层架构,并明白为什么要学习MyBatis框架
  • 建立maven项目,从零开始一步一步把MyBatis环境搭起来,并完成一个简单的查询sql操作
  • 完成查询之后,举一反三,完成一个简单的插入sql操作
  • MyBatis设置打印日志、一些工具类的介绍、用idea创建MyBatis的配置文件模板
  • 使用MyBatis的动态代理机制简化编程
  • MyBatis的sql传参
  • 传参时 $ 和 # 的区别
  • 动态sql相关
  • 分页插件使用

当然自己也就学了一天,所以也并没有多么深入,后续会继续写,小伙伴如果有问题或者发现有什么不对的地方,欢迎与我进行联系。

软件开发常用三层架构

  • 界面层(Spring MVC框架):表示层、视图层,主要功能是接受用户的数据,显示请求的处理结果。
  • 业务逻辑层(Spring框架):接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
  • 数据访问层(MyBatis框架):与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。

三层的处理请求的交互

  • 用户—> 界面层—>业务逻辑层—>数据访问层—>DB数据库

准备工作及要求

我的本机mysql环境:springdb数据库内创建一个student表,里面有两组数据。

小伙伴们可以用自己的sql可视化工具创建这个表,并添加两条数据即可。

新建一个maven项目

在src目录下,在默认的main文件夹下,添加java和resources两个文件夹,并分别将其标记为Sources Boot

和Resources Boot文件,在java文件夹中创建我们的包,如我的是cn.gs。

具体配置

先把步骤贴上面,我们根据这几个步骤做就可以

1
2
3
4
5
6
7
8
9
10
11
12
1.mysql新建student表
2.加入maven的mybatis依赖,mysql驱动的依赖
3.创建实体类,Student--保存表中的一行数据
4.创建持久层的dao接口,定义操作数据库的方法
5.创建一个mybatis的配置文件
叫做sql映射文件:写sql语句的,一般一个表一个sql文件
这个文件是xml文件,文件名与接口文件名一样
6.创建mybatis的主配置文件
一个项目就是一个配置文件
主配置文件提供了数据库的连接信息和sql映射文件的位置信息
7.创建使用mybatis类
通过mybatis来访问数据库
  1. mysql中插入学生表,已完成

  2. maven的pom.xml配置文件中,依赖项中加入mybatis和mysql驱动包,并在编译build里面加入扫描到.xml的配置。pom.xml文件如下

    可能直接用这上面的依赖项的版本会提示找不到,小伙伴们要根据直接的maven仓库自己去选择自己有的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.gs</groupId>
<artifactId>mybatis-blog-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>mybatis-blog-test Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
<scope>compile</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>

<build>
<!--配置能编译.xml文件-->
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
  1. 在cn.gs下创建一个domain包,包下面创建一个Student类
1
2
3
4
5
6
7
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
//再生成它的 toString 和 getter/setter方法
}
  1. 在cn.gs下创建一个dao包,包下面创建一个StudentDao接口
1
2
3
4
public interface StudentDao {
//查询student表所有数据
public List<Student> selectStudents();
}
  1. 创建mybatis的配置文件,叫做sql映射文件,文件名与接口文件名一样

    即在dao包下创建StudentDao.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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="cn.gs.dao.StudentDao">
<select id="selectStudents" resultType="cn.gs.domain.Student">
select id,name,email,age from Student order by id
</select>
</mapper>
<!--namespace: 唯一值,要求你使用dao接口的全限定名称-->
<!--select 表示执行查询,也可用其他,如update、delete、insert等-->
<!--id: 执行sql的唯一标识,要求你使用接口中定义的方法名称-->
<!--resultType:表示返会结果的类型,如我们查询得到的就是Student类,写全限定名称-->
  1. 在resources目录下创建mybatis.xml作为主配置文件,里面定义连接的参数、配置等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?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>
<!--环境配置 : 数据库连接信息-->
<environments default="mydev">
<!-- id: 一个唯一值,自定义,表示环境名称-->
<environment id="mydev">
<!-- transactionManager: mybatis的事物类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事物处理)-->
<transactionManager type="JDBC"/>
<!-- dataSource: 表示数据源,连接数据库-->
<dataSource type="POOLED">
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--mysql中我的用户名:root-->
<property name="username" value="root"/>
<!--root对应的登录密码:root-->
<property name="password" value="root"/>
</dataSource>
</environment>

<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--sql映射文件-->
<mappers>
<mapper resource="cn/gs/dao/StudentDao.xml"/>
</mappers>
</configuration>
  1. 在cn.gs下面创建一个APP类,完成测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class App 
{
public static void main( String[] args ) throws IOException {
//访问mybatis读取Student数据
//1.定义mybatis主配置文件的名称,从类路径的跟开始(target/classes)
String config = "mybatis.xml";
//2.读取这个config文件
InputStream is = Resources.getResourceAsStream(config);
//3.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(is);
//5.【重要】获取SqlSession对象,从SqlSessionFactory中获取
SqlSession sqlSession = factory.openSession();
//6.指定要执行的sql语句的表示,sql映射文件中的namesapce+ "." +标签的id值
String sqlId = "cn.gs.dao.StudentDao" + "." + "selectStudents";
//7.执行sql语句
List<Student> list = sqlSession.selectList(sqlId);
list.forEach(stu -> System.out.println(stu));
//8.关闭SqlSession对象
sqlSession.close();
}
}

这样我们的MyBatis就快速入门了,这个过程确实会报不少错,但我们一定不要放弃,环境的配置虽然挺麻烦,但是如果这点问题都不去自己解决,那谈什么nb的技术岂不是天方夜谭了!加油!

用MyBatis简单插入一条sql数据

前面我们学会了MyBatis的配置和简单使用,查询了sql的Student表数据,这次我们用它向Student表插入一条学生信息。

  1. 在StudentDao类中新添加一条方法:public int insertStudent(Student student);

  2. 在StudentDao.xml配置文件的mapper中新添加一条insert项

    1
    2
    3
    <insert id="insertStudent">
    insert into student values(#{id},#{name},#{email},#{age})
    </insert>

括号中的 #{xx} 表示函数传的参数student的对应值,就是这样的写法,会用即可。

  1. 在测试文件中,要把将要执行的sql语句的表示修改一下,再用SqlSession的insertStudent方法执行,最后还要设置一下提交事务操作。

    1
    2
    3
    String sqlId = "cn.gs.dao.StudentDao" + "." + "insertStudent";//插入方法
    int num = sqlSession.insert(sqlId, student);//执行,返回改变的行数
    sqlSession.commit();//提交事务

MyBatis设置打印日志

在MyBatis的主配置文件mybatis.xml中的configuration内添加一个setting即可

1
2
3
4
<!--设置输出日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

MyBatis主要类的介绍

  • Resources: mybatis中的一个类, 负责读取主配置文件
    1
    InputStream in = Resources.getResourceAsStream("mybatis.xml");
  • SqlSessionFactoryBuilder : 创建SqlSessionFactory对象
    1
    2
    3
    SqlSessionFactoryBuilder builder  = new SqlSessionFactoryBuilder();
    //创建SqlSessionFactory对象
    SqlSessionFactory factory = builder.build(in);
  • SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。
    1
    2
    3
    4
    5
    6
    7
    SqlSessionFactory:  接口,接口实现类: DefaultSqlSessionFactory
    SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();

    openSession()方法说明:
    1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
    2. openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
    openSession(false) 非自动提交事务的SqlSession对象
  • SqlSession:
    1
    2
    3
    4
    5
    SqlSession接口 :定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
    SqlSession接口的实现类DefaultSqlSession

    使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
    在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。

MyBatis工具类使用

在utils包下创建一个MyBatisUtil类,作为MyBatis的工具类,它会返回一个SqlSession对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyBatisUtil {
static SqlSessionFactory factory = null;
//使用静态代码块,只创建一个SqlSessionFactory类即可
static {
String config = "mybatis.xml";
try {
InputStream is = Resources.getResourceAsStream(config);
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if(factory!=null){
sqlSession = factory.openSession();
}
return sqlSession;
}
}

测试类中创建一个方法,使用这个测试类,用的时候直接通过类名加方法名获取SqlSession对象,然后定义sql的ID标识字符串,将其装载在sqlSession对象里执行即可。

1
2
3
4
5
6
@Test
public void MyBatisUtilUse(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
String sqlId = "cn.gs.dao.StudentDao" + "." + "selectStudents";
List<Student> list = sqlSession.selectList(sqlId);
}

创建MyBatis的mapper和配置文件模板

创建MyBatis的配置文件模板

File –> Settings –> Editor –> File and Code Templates –> file选项,点击 + 创建新的模板

Name填入 mybatis-config,Extension填入 xml,页面格式写入以下内容,点击OK即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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"/>
</settings>

<!--环境配置 : 数据库连接信息-->
<environments default="mydev">
<!-- id: 一个唯一值,自定义,表示环境名称-->
<environment id="mydev">
<!-- transactionManager: mybatis的事物类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事物处理)-->
<transactionManager type="JDBC"/>
<!-- dataSource: 表示数据源,连接数据库-->
<dataSource type="POOLED">
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--连接数据库的用户名-->
<property name="username" value="root"/>
<!--连接数据库的用户名密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/gs/dao/StudentDao.xml"/>
</mappers>
</configuration>
创建MyBatis的mapper模板

File –> Settings –> Editor –> File and Code Templates –> file选项,点击 + 创建新的模板

Name填入 mybatis-mapper,Extension填入 xml,页面格式写入以下内容,点击OK即可

1
2
3
4
5
6
7
8
9
10
<?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="cn.gs.dao.StudentDao">
<select id="selectStudents" resultType="cn.gs.domain.Student">
select id,name,email,age from Student order by id
</select>
</mapper>

使用MyBatis的动态代理机制

使用MyBatis的动态代理机制,使用SQLSession.getMapper(dao接口)

getMapper能获取dao接口对应的实现类对象,这样获取的dao类就能执行接口中相对应的方法了。

1
2
3
4
5
6
7
8
@Test
public void MyBatisProxyTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//调用dao的方,执行数据库的查询方法
List<Student> students = dao.selectStudents();
students.forEach(stu-> System.out.println(stu));
}

如果要执行插入操作同样的道理,执行dao的insertStudent方法即可。

MyBatis的sql传参

传递一个简单类型的参数
  1. 在StudentDao接口中添加方法

    1
    Student selectStudentById(Integer id);//根据id查询,返回Student对象
  2. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectStudentById" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student where id = #{id}
    </select>
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void selectByIdTest(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    Student student = mapper.selectStudentById(1001);
    System.out.println(student);
    }

传递多个简单类型的参数(使用命名参数)
  1. 在StudentDao接口中添加方法

    1
    2
    3
    //传递多个参数,命名参数,在形参定义的前面加入 @Param("自定义参数名称")
    List<Student> selectMultiParam(@Param("myname") String name,
    @Param("myage") Integer age);
  2. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectMultiParam" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student where name = #{myname} or age = #{myage}
    </select>
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void selectMultiTest(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    List<Student> students = mapper.selectMultiParam("zhangsan", 22);
    System.out.println(students);
    }

传递多个简单类型的参数(使用对象)
  1. 和上一个一样,我们传name和age两个参数来进行查询,我们可以把这两个参数封装为一个对象,然后直接用 #{xx} 来实现sql查询即可

    1
    2
    3
    4
    5
    6
    // 在vo包下面创建一个QueryParam对象,封装name和age成员变量
    public class QueryParam {
    private String paramName;
    private Integer paramAge;
    ....;//实现其getter/setter,toString()方法
    }
  2. 在StudentDao接口中添加方法

    1
    2
    //用对象来传递多个参数
    List<Student> selectMultiObject(QueryParam queryParam);
  3. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectMultiObject" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student where name = #{paramName} or age = #{paramAge}
    </select>
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void selectMultiObjectTest(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    QueryParam queryParam = new QueryParam();
    queryParam.setParamName("zhangsan");
    queryParam.setParamAge(22);
    List<Student> students = mapper.selectMultiObject(queryParam);
    System.out.println(students);
    }

    当然我们也可以选择用原有的Student类来作为传参对象,它本来就有name和age成员变量,这样也是可以的!

传递多个简单类型的参数(按位置,了解即可)
  1. 在StudentDao接口中添加方法

    1
    2
    //传递多个参数,按位置
    List<Student> selectMultiPosition(String name,Integer age);
  2. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectMultiPosition" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student where name = #{arg0} or age = #{arg1}
    </select>

    #{arg0}#{arg0} 表示参数位置:第一个参数和第二个参数

  3. 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void selectMultiPositionTest(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    List<Student> students = mapper.selectMultiPosition("zhangsan",22);
    System.out.println(students);
    }

$ 和

前面我们传参时候在StudentDao.xml中,用的都是 #{} ,进行参数传递,用 ${} 其实也可以,但是会有问题。

那么这两个东西有什么区别呢?我们先把上面传递一个简单的参数用${}来替换一下,看看有什么区别?

还是原来的三步,只不过换了一下名字,在把mapper文件中那条select中的 #{} 换成了 ${} 即可

  1. 在StudentDao接口中添加方法

    1
    2
    //用${}传递一个参数
    Student selectStudentBy$(@Param("id") Integer id);
  2. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectStudentBy$" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student where id = ${id}
    </select>
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void selectStudentByIdWith$Test(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    Student student = mapper.selectStudentBy$(1001);
    System.out.println(student);
    }

观察输出的结果,发现可以呀,没问题,还是能查询出张三同学。

但是其实打印的日志不太一样,我把两张图片放出来,我们且看一看。

直接上结论:

  • #{}:是以预编译的形式,将参数设置到sql语句中;能防止sql注入
  • ${}:取出的值直接拼装在sql语句中;会有安全问题(sql注入)
面试题:# 和 $区别
1. **#使用 ?在sql语句中做站位的,使用PreparedStatement执行sql,效率高**
2. **#能够避免sql注入,更安全。**
3. **$不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低**
4. **$有sql注入的风险,缺乏安全性。**
5. **$:可以替换表名或者列名**
例:用${}进行排序
  1. 在StudentDao接口中添加方法

    1
    List<Student> selectStudentsSortBy$(@Param("option")String option);
  2. 在StudentDao.xml接口中添加对应的select

    1
    2
    3
    <select id="selectStudentsSortBy$" resultType="cn.gs.domain.Student">
    select id,name,email,age from Student order by ${option}
    </select>
  3. 测试

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void selectStudentsSortBy$Test(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao mapper = sqlSession.getMapper(StudentDao.class);
    List<Student> students = mapper.selectStudentsSortBy$("name");
    System.out.println(students);
    }

动态sql

在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。

实体符号表:

< 小于 &lt;
> 大于 $gt;
<= 小于等于 $lt;=
>= 大于等于 $gt;=
if

接口方法

1
List<Student> selectStudentIf(Student student);

mapper文件

1
2
3
4
<select id="selectStudentIf" resultType="cn.gs.domain.Student">
select id,name,email,age from Student where
<if test="id!=null and id!= ''">id &gt; #{id}</if>
</select>

测试方法

1
2
3
4
5
6
7
8
9
@Test
public void selectIfTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1002);
List<Student> students = mapper.selectStudentIf(student);
System.out.println(students);
}

where

标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后 的所有条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会 严重影响查询效率。 使用标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。需要注意的是,第一个标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错, 系统会将多出的 and 去掉。但其它中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错 。

接口方法

1
List<Student> selectStudentWhere(Student student);

mapper文件

1
2
3
4
5
6
7
8
9
10
11
<select id="selectStudentWhere" resultType="cn.gs.domain.Student">
select id,name,email,age from Student
<where>
<if test="name!=null and name!= ''">
and name = #{name}
</if>
<if test="id>0">
and id &gt; #{id}
</if>
</where>
</select>

测试方法

1
2
3
4
5
6
7
8
9
10
@Test
public void selectWhereTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1002);
student.setName("liubei");
List<Student> students = mapper.selectStudentWhere(student);
System.out.println(students);
}

foreach

标签用于实现对于数组与集合的遍历。对其使用,需要注意:

➢ collection 表示要遍历的集合类型, list ,array 等。

➢ open、close、separator 为对遍历内容的 SQL 拼接。

语法:

1
<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">#{item 的值}</foreach>

需求:查询学生id为:1001、1002、1003

接口方法

1
2
//动态sql,foreach
List<Student> selectStudentForeach(List<Integer> list);

mapper文件

1
2
3
4
5
6
7
8
9
<select id="selectStudentForeach" resultType="cn.gs.domain.Student">
select id,name,email,age from Student
<if test="list!=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" item="stuid" separator=",">
#{stuid}
</foreach>
</if>
</select>

测试方法

1
2
3
4
5
6
7
8
9
10
11
@Test
public void selectForeachTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> students = mapper.selectStudentForeach(list);
System.out.println(students);
}

代码片段

标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用 子标签。 该标签可以定义 SQL 语句中的任何部分,所以子标签可以放在动态 SQL 的任何位置。

接口方法

1
List<Student> selectStudentSqlFragment(List<Integer> list);

mapper文件

1
2
3
4
5
6
7
8
9
10
11
12
<sql id="selectSql">
select id,name,email,age from Student
</sql>
<select id="selectStudentSqlFragment" resultType="cn.gs.domain.Student">
<include refid="selectSql"></include>
<if test="list!=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" item="stuid" separator=",">
#{stuid}
</foreach>
</if>
</select>

测试方法

1
2
3
4
5
6
7
8
9
10
11
@Test
public void selectSqlFragmentTest(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> students = mapper.selectStudentSqlFragment(list);
System.out.println(students);
}

Mybatis 通用分页插件——PageHelper

实现步骤

Maven的xml配置文件加入依赖项
1
2
3
4
5
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
mybatis.xml中配置插件
1
2
3
4
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
用PageHelper 对象使用插件

查询语句之前调用 PageHelper.startPage 静态方法。 除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。 在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个 方法后的第一个 MyBatis 查询方法会被进行分页。

1
2
3
4
5
6
7
8
@Test
public void pageTest(){
PageHelper.startPage(2,2);
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.selectStudents();
students.forEach(student -> System.out.println(student));
}