MyBatis学习笔记五

15 篇文章 0 订阅

MyBatis 框架动态 SQL

动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有< if >、< where >、< choose >、< foreach >等。MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。

动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题

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

1、if

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:< if test=”条件” > sql 语句的部分 < /if >
接口方法:

List<Student> selectStudentIf(Student student);

mapper文件:

    <select id="selectStudentIf" resultType="com.b0kuwa.entity.Student">
        select * from student where 1 = 1
        <if test="name != null and name != ''">
            and name = #{name}
        </if>
        <if test="age > 0">
            or age &gt; #{age}
        </if>
    </select>

测试:

    @Test
    public void selectStudentIf() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Student student = new Student();
        student.setName("张三");
        student.setAge(18);
        List<Student> students = dao.selectStudentIf(student);
        students.forEach(stu -> System.out.println(stu));
        sqlSession.close();
    }

在这里插入图片描述

2、where

if标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有if条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL
出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会
严重影响查询效率。

使用where标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加where 子句。需要注意的是,第一个标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,系统会将多出的 and 去掉。但其它中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错。
语法:< where > 其他动态 sql < /where >

接口方法:

  List<Student> selectStudentWhere(Student student);

mapper文件:

    <select id="selectStudentWhere" resultType="com.b0kuwa.entity.Student">
        select * from student
        <where>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="age > 0">
                or age &gt; #{age}
            </if>
        </where>
    </select>

测试:

    @Test
    public void selectStudentWhere() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Student student = new Student();
        student.setName("张三");
        student.setAge(18);
        List<Student> students = dao.selectStudentWhere(student);
        students.forEach(stu -> System.out.println(stu));
        sqlSession.close();
    }

在这里插入图片描述

3、foreach

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

  • collection 表示要遍历的集合类型, list ,array 等。
  • open、close、separator 为对遍历内容的 SQL 拼接。

语法:

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

3.1 遍历 List<简单类型>

表达式中的 List 使用 list 表示,其大小使用 list.size 表示。

接口方法:

    List<Student> selectForeachOne(List<Integer> idlist);

mapper文件:

    <select id="selectForeachOne" resultType="com.b0kuwa.entity.Student">
        select * from student where id in
        <foreach collection="list" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>

测试:

    @Test
    public void selectForeachOne() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Integer> list = new ArrayList<>();
        list.add(1002);
        list.add(1004);
        list.add(1006);
        List<Student> students = dao.selectForeachOne(list);
        students.forEach(student -> System.out.println(student));
        sqlSession.close();
    }

在这里插入图片描述

3.2 遍历 List<对象类型>

接口方法:

  List<Student> selectForeachTwo(List<Student> stulist);

mapper文件:

    <select id="selectForeachTwo" resultType="com.b0kuwa.entity.Student">
        select * from student where id in
        <if test="list !=null and list.size > 0">
            <foreach collection="list" item="student" open="(" close=")" separator=",">
                #{student.id}
            </foreach>
        </if>
    </select>

测试:

    @Test
    public void selectForeachTwo() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> list = new ArrayList<>();
        Student student = new Student();
        student.setId(1001);
        list.add(student);
        student = new Student();
        student.setId(1003);
        list.add(student);
        student = new Student();
        student.setId(1006);
        list.add(student);
        List<Student> students = dao.selectForeachTwo(list);
        students.forEach(stu -> System.out.println(stu));
        sqlSession.close();
    }

在这里插入图片描述

4、sql代码片段

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

接口方法:

    List<Student> selectStudentSqlFragment();

mapper文件:

    <sql id="studentSqlFragment">
        select * from student
    </sql>

    <select id="selectStudentSqlFragment" resultType="com.b0kuwa.entity.Student">
        <include refid="studentSqlFragment"/> order by age
    </select>

测试:

    @Test
    public void selectStudentSqlFragment() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> students = dao.selectStudentSqlFragment();
        students.forEach(student -> System.out.println(student));
        sqlSession.close();
    }

在这里插入图片描述

5、PageHelper

PageHelper GitHub
PageHelper 支持多种数据库:

  1. Oracle
  2. Mysql
  3. MariaDB
  4. SQLite
  5. Hsqldb
  6. PostgreSQL
  7. DB2
  8. SqlServer(2005,2008)
  9. Informix
  10. H2
  11. SqlServer2012
  12. Derby
  13. Phoenix

5.1 基于 PageHelper 分页

1)加入maven 坐标
 	<dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>
2)加入 plugin 配置(mybatis主配置文件中)

在< environments >之前加入

<plugins> 
	<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
3)PageHelper 对象

查询语句之前调用 PageHelper.startPage 静态方法。

除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。

在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个 MyBatis 查询方法会被进行分页。

5.2 案例

接口方法:

    List<Student> selectAll();

mapper文件:

    <select id="selectAll" resultType="com.b0kuwa.entity.Student">
        select * from student
    </select>

测试:

    @Test
    public void selectAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        PageHelper.startPage(1,3);
        List<Student> students = dao.selectAll();
        students.forEach(student -> System.out.println(student));
        sqlSession.close();
    }

在这里插入图片描述

6、MyBatis 配置文件补充

6.1 主配置文件

主配置文件特点:

  1. 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">
  1. 根元素,< configuration >
  2. 主要包含内容:
    1)定义别名
    2)数据源
    3)mapper 文件

6.2 dataSource 标签

Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml
配置文件中,通过< dataSource type=”pooled” >来实现 Mybatis 中连接池的配置。

6.2.1 DataSource类型

在这里插入图片描述
Mybatis 将数据源分为三类:
UNPOOLED :不使用连接池的数据源
POOLED : 使用连接池的数据源
JNDI :使用 JNDI 实现的数据源

其中 UNPOOLED ,POOLED 数据源实现了 javax.sql.DataSource 接口, JNDI 和前面两个实现方式不同,了解可以。
在这里插入图片描述

6.2.2 dataSource 配置

在 MyBatis.xml 主配置文件,配置 dataSource:

<dataSource type="POOLED">
	<!--数据库的驱动类名-->
	<property name="driver" value="com.mysql.jdbc.Driver"/>
	<!--连接数据库的url字符串-->
	<property name="url" value="jdbc:mysql://192.168.31.205:3306/school"/>
	<!--访问数据库的用户名-->
	<property name="username" value="root"/>
	<!--密码-->
	<property name="password" value="111111"/>
</dataSource>

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即:type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

6.3 事务

1)默认需要手动提交事务

Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection对象的 commit(), rollback() .

Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交

<transactionManager type="JDBC"/>

该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。

  • JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。从日志的输出信息中可以看到。
    在这里插入图片描述
  • MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。
2)自动提交事务

设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
在这里插入图片描述
有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。

session = factory.openSession(true);

再执行 insert 操作,无需执行 session.commit(),事务是自动提交的

6.4 使用数据库属性配置文件

为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis主配置文件需要从这个属性文件中读取这些数据。

1) 在 classpath 路径下,创建 properties 文件

在 resources 目录创建 jdbc.properties 文件,文件名称自定义。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.31.205:3306/school
jdbc.username=root
jdbc.password=111111
2) 使用 properties 标签

修改主配置文件,文件开始位置加入:
在这里插入图片描述

3) 使用 key 指定值

在这里插入图片描述

6.5 typeAliases(类型别名)

Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发,主要使用在< select resultType=”别名” >mybatis.xml 主配置文件定义别名:

    <typeAliases>
        <!--
            定义单个类型的别名
            type:类型的全限定名称
            alias:自定义别名
        -->
        <typeAlias type="com.b0kuwa.entity.Student" alias="student"/>
        <!--
            批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
            name:包名
        -->
        <package name="com.b0kuwa.entity"/>
    </typeAliases>

mapper.xml 文件,使用别名表示类型

    <select id="selectAll" resultType="student">
        select * from student
    </select>

6.6 mappers(映射器)

1) < mapper resource=" " / >

使用相对于类路径的资源,从 classpath 路径查找文件
例如:< mapper resource=“com/b0kuwa/dao/StudentDao.xml” / >

2) < package name=""/ >

指定包下的所有 Dao 接口
如:< package name=“com.b0kuwa.dao”/ >
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值