第一个Mybatis程序

什么是mybatis?

  MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
  iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs):数据访问对象
  MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。


查看官方文档:Mybatis3官方文档



思路:搭建环境——>导入Mybatis——>编写代码——>测试



编写的同步练习代码,以供复习。
链接:https://pan.baidu.com/s/1WArWnbfA7t7hJD9d3jYeJg
提取码:k8mi


1.1搭建环境

1.1.1搭建数据库:

CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(
	`id` INT(20) NOT NULL PRIMARY KEY,
	`name` VARCHAR(30) DEFAULT NULL,
	`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,'叶不羞','yebuxiu'),
(2,'提莫','timo'),
(3,'黄少天','huangshaotian');

1.2 新建项目

1,创建一个普通的maven项目
在这里插入图片描述
2,删除src目录删除,将其作为一个父工程
3,导入依赖
如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

    <dependencies>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

1.3 创建一个模块

编写mybatis的核心配置文件(连接数据库)
  在resource文件夹下建立mybatis-config.xml文件,XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)

<?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核心配置文件-->
<configuration>
    <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&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

连接数据库时若出现此错误:
Server returns invalid timezone. Go to ‘Advanced’ tab and set 'serverTimezon
服务器返回无效时区:需要设置时区
第一步:连接数据库 mysql -hlocalhost -uroot -p
第二步:输入:show variables like’%time_zone’;
第三步:输入set global time_zone = ‘+8:00’;

编写mybatis工具类
  编写工具类的目的:从 XML 中构建 SqlSessionFactory,从 SqlSessionFactory 中获取 SqlSession,而SqlSession 提供了在数据库执行 SQL 命令所需的所有方法(就像JDBC中的PreparedStatement所充当的作用)

在java文件夹中创建目录结构:
com.mofei.dao
com.mofei.utils
com.mofei.pojo

在utils文件夹下建立MybatisUtils类:

package com.mofie.utils;

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;

/**
 * @author mofei
 * @create 2020-11-9:45
 */
public class MybatisUtils {
    //第一步:获取SQLSessionFactory
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "mybatis-config.xml";
            //使用Resource工具类加载资源文件
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	//获取SqlSession
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }
}

1.4 编写代码

●编写实体类(在pojo文件夹下建立User类:数据库对象映射的java类)

package com.mofie.pojo;

/**
 * @author mofei
 * @create 2020-11-10:12
 */
public class User {
    private int Id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        Id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return Id;
    }

    public void setId(int id) {
        Id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "Id=" + Id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

●编写Dao接口

package com.mofie.dao;

import com.mofie.pojo.User;

import java.util.List;

/**
 * @author mofei
 * @create 2020-11-10:20
 */
public interface UserMapper {
	//查询全部用户
    public List<User> getUserList();
}

●编写Dao接口的实现类
(用UserMapper.xml文件代替原来的UserDaoImpl.java去完成接口的实现类)
但是UserMapper接口怎么与UserMapper.xml实现文件连接起来呢?

namespace:绑定一个对应Dao/Mapper接口
id:绑定对应接口中的方法
resultType:返回查询结果的类型(使用全类名)
parameterType:方法中传递的参数类型

(下边有详细的介绍)

<?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">

<!-- namespace绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.mofie.dao.UserMapper">
	<!--查询全部用户-->
    <select id="getUserList" resultType="com.mofie.pojo.User">
    select * from mybatis.user
    </select>
</mapper>

如下是Mapper标签下所容纳的标签:对数据库的一些操作
在这里插入图片描述
●编写test测试类(在test/java文件夹下建立与main/java同样的结构:com.mofei.dao)
在dao文件夹下建立UserDaoTest类用于测试:

public class UserDaoTest {
    @Test
    public void test(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = mapper.getUserList();
        for (User user : list) {
            System.out.println(user);
        }

        //关闭SqlSession
        sqlSession.close();
    }
}

然后,运行出现了异常:org.apache.ibatis.binding.BindingException: Type interface com.mofie.dao.UserMapper is not known to the MapperRegistry.
【绑定异常:com.mofei.dao.UserMapper这个接口没有注册映射】
在这里插入图片描述
解决办法: 在configuration核心配置文件中添加映射器(Mappers):你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等,这些配置会告诉 MyBatis 去哪里找映射文件。
常用的方式:(常用的为前三种方式)

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="com/mofei/dao/UserMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="com.mofie.dao.UserMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="com.mofei.dao"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

●配置完成之后再去测试:出现了异常:java.lang.ExceptionInInitializerError:初始化异常
它没有找到配置的com/mofei/dao/UserMapper.xml资源文件
在这里插入图片描述
然后去找target/classes文件目录下的内容如下:
在这里插入图片描述
发现并没有UserMapper.xml这个文件;说明没有进行资源过滤,导致资源导出失败。
maven由于它的约定大于配置,之后会遇到我们写的配置文件,无法被导出或者无法生效的问题,解决方案:
  添加在父工程或子工程的pom.xml中均可

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

然后,再去测试。啊!之后不出意外地又报了异常
然后手动clear并test了一下maven,发现了调试的异常:Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project mybatis-01: There are test failures.【在项目mybatis-01上执行目标org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test(默认为test):存在测试失败。】
在这里插入图片描述
解决方案:在build标签中添加此插件

    <build>
    ......
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
        </plugins>
    ......    
    </build>

然后再手动test一下,报了个警告:Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!【使用平台编码(实际上是UTF-8)来复制过滤过的资源,也就是说,构建是依赖于平台的!】
在这里插入图片描述
解决方案:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

???

错误警告都搞完了,怎么还是显示没找到接口???
前: 有异常
在这里插入图片描述
后: 运行正常
在这里插入图片描述
前者没有提示,后者idle有提示,写完运行通过。。。ε=(´ο`*)))唉?不对劲,他两不是一样的吗?定睛一看,文件名写错了,原来是建文件名的时候手残建错了。。。此波不亏,赚了一个异常和一个警告。(把之前加的那个maven-surefire-plugin插件删掉不收影响)
●打印测试结果

User{Id=1, name='叶不羞', pwd='yebuxiu'}
User{Id=2, name='提莫', pwd='timo'}
User{Id=3, name='黄少天', pwd='huangshaotian'}

1.5 小结

思路大致可分为八部分:
1,创建数据库
2,导入依赖
3,编写mybatis核心配置文件
4,编写工具类MybatisUtils.java
5,编写实体类
6,编写接口
7,编写接口实现类文件
8,测试


查看官方文档:Mybatis3官方文档


2,CRUD

2.1 根据ID查询用户

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //根据ID查询用户
    User getUserById(int id);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--根据ID查询用户-->
    <select id="getUserById" resultType="com.mofei.pojo.User" parameterType="int">
        select * from mybatis.user where id = #{id}
    </select>
    ......
</mapper>

●其中
namespace:绑定一个对应的Dao/Mapper接口
id:绑定的接口下的方法名
resultType:表示查询返回的结果类型(当没有添加别名限定时,要使用完全限定名)
parameterType:方法中的参数,若方法中没有参数,这项可以不写

进行测试:

    @Test
    public void getUserById(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        sqlSession.close();
    }

测试结果:

User{Id=1, name='叶不羞', pwd='yebuxiu'}

…………………………………………………………………………………………………………

2.2 插入一个用户

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //插入一个用户
    int addUser(User user);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--插入一个用户-->
    <insert id="addUser" parameterType="com.mofei.pojo.User">
        insert into mybatis.user(id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>
    ......
</mapper>

进行测试:

    @Test
    public void addUser(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.addUser(new User(4, "爪哇", "zawa"));
        System.out.println("i = " + i);
        sqlSession.close();
    }

测试结果并刷新数据库:

i = 1

在这里插入图片描述
通过结果显示:进行了插入操作,但并没有成功的将数据插入到数据库中。
原因:对数据库表中数据能产生影响的增删改操作需要提交事务

然后再测试中添加**sqlSession.commit();**提交事务,然后刷新数据库:数据成功插入
在这里插入图片描述
…………………………………………………………………………………………………………

2.3 修改用户

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //插入一个用户
    int updateUser(User user);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--修改用户-->
    <update id="updateUser" parameterType="com.mofei.pojo.User">
        update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}
    </update>
    ......
</mapper>

进行测试:

    @Test
    public void updateUser(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.updateUser(new User(4, "荷花", "hehua"));
        System.out.println("i = " + i);
        sqlSession.commit();
        sqlSession.close();
    }

测试结果如下:

i = 1

在这里插入图片描述
…………………………………………………………………………………………………………

2.4 删除用户

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //插入一个用户
    int deleteUser(int id);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--删除一个用户-->
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id}
    </delete>
    ......
</mapper>

进行测试:

    @Test
    public void deleteUser(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(4);
        System.out.println("i = " + i);
        sqlSession.commit();
        sqlSession.close();
    }

测试结果显示:

i = 1

在这里插入图片描述

…………………………………………………………………………………………………………

2.5 万能的Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map!
使用Map实现添加操作:
在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //使用Map实现添加操作
    int addUser2(Map<String,Object> map);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--使用Map实现添加操作-->
    <insert id="addUser2" parameterType="map">
        insert into mybatis.user (id,name,pwd) values (#{userId},#{userName},#{userPwd})
    </insert>
    ......
</mapper>

进行测试:

    @Test
    public void addUser2(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("userId",4);
        map.put("userName","寒烟柔");
        map.put("userPwd","yanrou");

        int i = mapper.addUser2(map);
        System.out.println("i = " + i);
        sqlSession.commit();
        sqlSession.close();
    }

测试结果:

i = 1

在这里插入图片描述

2.6 模糊查询

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //模糊查询,找出名字中含有叶的用户
    List<User> getUserLike(String value);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<!--模糊查询,找出名字中含有叶的用户-->
    <select id="getUserLike" resultType="com.mofei.pojo.User">
        select * from mybatis.user where name like #{value}
    </select>
    ......
</mapper>

进行测试:

    @Test
    public void getUserLike(){
        //第一步:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二步:获得接口
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserLike("%叶%");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.commit();
        sqlSession.close();
    }

测试结果:

User{Id=1, name='叶不羞', pwd='yebuxiu'}
User{Id=5, name='老叶', pwd='ye'}

以上为第一种写法:
第二种为:更改为下列语句,结果不变
sql语句:select * from mybatis.user where name like “%”#{value}"%"
测试中调用语句:List userList = mapper.getUserLike(“叶”);

2.7 小结

1,CRUD操作步骤步骤:
(1),编写接口方法
(2),编写接口方法对应的sql语句
(3),测试
2,增删改操作需要提交事务
3,使用Map传递参数时,直接在sql中取出key即可!【parameterType=“map”】
对象传递参数时,直接在sql中取对象的属性即可!【parameterType=“Object”】
只有一个基本类型参数的情况下,可以直接在sql中取到。多个参数用Map或注解


查看官方文档:Mybatis3官方文档


3,配置解析

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
● configuration(配置)
  ○ properties(属性)
  ○ settings(设置)
  ○ typeAliases(类型别名)
  ○ typeHandlers(类型处理器)
  ○ objectFactory(对象工厂)
  ○ plugins(插件)
  ○ environments(环境配置)
     ■ environment(环境变量)
       ■ transactionManager(事务管理器)
       ■ dataSource(数据源)
  ○ databaseIdProvider(数据库厂商标识)
  ○ mappers(映射器)

【这里所说的MyBatis 的配置文件就是以上所写Mybatis-config.xml配置文件】
在开头,在Mybatis-config.xml文件中进行如下配置:

<configuration>
    <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&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/mofei/dao/UserMapper.xml"/>
    </mappers>
</configuration>

3.1 环境配置(environments)

  MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
  不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。 所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推;其中< environments default=" ">中的default属性能默认的一套环境。
注意一些关键点:
  ● 默认使用的环境 ID(比如:default=“development”)。
  ● 每个 environment 元素定义的环境 ID(比如:id=“development”)。
  ● 事务管理器的配置(比如:type=“JDBC”)。
  ● 数据源的配置(比如:type=“POOLED”)。

3.1.1 事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
  • 提示 如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
3.1.2 数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

  • UNPOOLED
  • JNDI
  • POOLED
    在这里插入图片描述
3.1.3 小结

Mybatis可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
学会使用 配置多套运行环境!
Mybatis默认的事务管理器就是JDBC,连接池:POOLED

<transactionManager type="JDBC"/>
<dataSource type="POOLED">

3.2 属性(properties)

3.2.1 引入配置文件

我们可以通过properties属性来引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties配置文件】
编写数据库配置文件:db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456

在加入properties属性标签之前一定要知道的:configuration标签下的标签书写顺序为
properties>setting>typeAliases>typeHandlers>objectFactory>objectWrapperFactory>reflectorFactory>plugins>environments>databaseldProvider>mappers

引入配置文件

<configuration>
    <properties resource="db.properties"/>
    ......
        <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    ......
</configuration>
3.2.12 小结
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置:比如
    在这里插入图片描述
  • 如果两个文件有同一个字段,优先使用外部配置文件的

3.3 类型别名(typeAliases)

3.3.1 类型别名的命名方式

在这里插入图片描述
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
在这里插入图片描述

  • 给实体类起别名
    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.mofei.pojo.User" alias="User"/>
    </typeAliases>
    <select id="getUserList" resultType="User">
    <select id="getUserById" resultType="User" parameterType="int">
  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean:比如,扫描实体类的包,它默认的别名就是这个类的 类名首字母小写
    <typeAliases>
        <package name="com.mofei.pojo"/>
    </typeAliases>
    <select id="getUserList" resultType="user">
    <select id="getUserById" resultType="user" parameterType="int">
  • 使用注解指定别名:在指定包名的基础上,在包内实体类的类名上方加上注解,其注解值就是其别名
    <typeAliases>
        <package name="com.mofei.pojo"/>
    </typeAliases>
@Alias("User")
public class User {
    private int Id;
    private String name;
    private String pwd;
    ......

3.4 设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
在这里插入图片描述

在这里插入图片描述

3.5 映射器(mappers)

这是在1.4标题出现的绑定异常
运行出现了异常:org.apache.ibatis.binding.BindingException: Type interface com.mofie.dao.UserMapper is not known to the MapperRegistry.
【绑定异常:com.mofei.dao.UserMapper这个接口没有注册映射】
在这里插入图片描述
解决办法: 在configuration核心配置文件中添加映射器(Mappers):你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等,这些配置会告诉 MyBatis 去哪里找映射文件。
常用的方式:(常用的为前三种方式)

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="com/mofei/dao/UserMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="com.mofie.dao.UserMapper"/>
</mappers>

在使用< mapper class=" "/>时要注意的点:
●接口(UserMapper.java)和它的Mapper配置文件(UserMapper.xml)必须同名
●接口和它的Mapper配置文件必须在同一个包下

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="com.mofei.dao"/>
</mappers>

使用包扫描进行注入绑定得注意点跟使用< mapper class=" "/>时要注意的点一样

<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

查看官方文档:Mybatis3官方文档


4,作用域(Scope)和生命周期

  作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题
SqlSessionFactoryBuilder
  这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory
  SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession
  每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。


查看官方文档:Mybatis3官方文档


5,resultMap:解决属性名与字段名不一致的问题

出现的位置及在什么情况下使用ResultMap?
resultMap出现的位置:之前已经见过简单映射语句的示例,它们没有显式指定 resultMap

    <!--查询全部用户-->
    <select id="getUserList" resultType="User">
    select * from mybatis.user
  </select>

在这里插入图片描述
在什么情况下使用ResultMap:当实体类属性名与数据库字段名不一致时


数据库中的字段:
在这里插入图片描述
实体类User.java

public class User {
    private int id;
    private String name;
    private String password;
	......
}

进行测试:

    <!--查询全部用户-->
    <select id="getUserList" resultType="User">
    select * from mybatis.user
 	</select>

测试结果:

User{id=1, name='叶不羞', password='null'}
User{id=2, name='提莫', password='null'}
User{id=3, name='黄少天', password='null'}
User{id=4, name='寒烟柔', password='null'}
User{id=5, name='老叶', password='null'}

password属性一栏都为null,因为pwd在实体类中根据类型处理器找不到对应属性名的属性,打印输出是password属性一栏为初始化默认属性值null。

5.1解决方式一,使用别名:改写数据库语句表达式

    <!--查询全部用户-->
    <select id="getUserList" resultType="User">
    	select id,name,pwd password from mybatis.user
 	</select>

测试结果:

User{id=1, name='叶不羞', password='yebuxiu'}
User{id=2, name='提莫', password='timo'}
User{id=3, name='黄少天', password='huangshaotian'}
User{id=4, name='寒烟柔', password='yanrou'}
User{id=5, name='老叶', password='ye'}

5.2 解决方式二,使用resultMap:结果集映射

在不更改数据库语句的基础上处理别名问题
用法:
在这里插入图片描述
原来的resultType为结果返回类型,现将resultType替换为我resultMap,并将结果返回类型写入resultMap中,即type=“User”,而且resultMap值必须与结果集映射中的id值相同,实现绑定。
其中属性column代表数据库中的字段
  属性property代表实体类中相应的属性

在这里插入图片描述
测试结果:

User{id=1, name='叶不羞', password='yebuxiu'}
User{id=2, name='提莫', password='timo'}
User{id=3, name='黄少天', password='huangshaotian'}
User{id=4, name='寒烟柔', password='yanrou'}
User{id=5, name='老叶', password='ye'}

6 日志

如果一个数据块操作出现了异常,我们需要排错。日志就是最好的助手!
在这里插入图片描述
SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING
在mybatis中具体使用哪个日志实现,在设置中设定。

6.1 STDOUT_LOGGING 标准日志输出

<!--mybatis核心配置文件-->
<configuration>
    ......
    <!--配置标准日志实现-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
	......
</configuration>

在这里插入图片描述

6.2 LOG4J

  Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
配置
第一步:在项目模块的pom.xml文件中插入log4j依赖

    <!--导入LOG4J依赖-->
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

第二步:在CLASSPATH下建立log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/mofei.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

第三步:配置log4j为日志的实现

<!--mybatis核心配置文件-->
<configuration>
    ......
    <!--配置标准日志实现-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
	......
</configuration>

在这里插入图片描述
同时将日志写入**./log/mofei.log**文件中
在这里插入图片描述

7,Limit实现分页

在dao/UserMapper.java接口中添加新的方法:

public interface UserMapper {
	......
    //limit分页
    List<User> getUserByLimit(Map<String,Integer> map);
    ......
}

在接口实现文件UserMapper.xml中添加映射

<mapper namespace="com.mofei.dao.UserMapper">
	......
	<select id="getUserByLimit" resultMap="UserMap" parameterType="map">
        select * from mybatis.user limit #{startIndex},#{pageSize}
    </select>
    ......
</mapper>

进行测试:

    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userList = mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

8,使用注解开发

8.1 注解配置

1,注解就是在接口上实现:

public interface UserMapper {
    //查询全部用户
    @Select("select * from mybatis.user")
    List<User> getUserList();
    ......
}

2,需要在核心配置文件中绑定接口

<configuration>
    ......
    <!--现在用注解取代了UserMapper.xml文件,
    就用不了resource属性绑定,只有一个接口文件,所以用class属性去绑定很合适-->
    <mappers>
        <mapper class="com.mofei.dao.UserMapper"/>
    </mappers>
</configuration>

3,测试

@Test
    public void getUserListTest(){
        SqlSession sqlSessioin = MybatisUtils.getSqlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSessioin.getMapper(UserMapper.class);
        List<User> list = mapper.getUserList();
        for (User user : list) {
            System.out.println(user);
        }
        sqlSessioin.close();
    }

测试结果:

User{id=1, name='叶不羞', pwd='yebuxiu'}
User{id=2, name='提莫', pwd='timo'}
User{id=3, name='黄少天', pwd='huangshaotian'}
User{id=4, name='寒烟柔', pwd='yanrou'}
User{id=5, name='老叶', pwd='ye'}

本质:反射机制实现
底层:动态代理

8.2 Mybatis详细的执行流程:

在这里插入图片描述

8.3 CRUD

  我们可以在工具类创建的时候实现自动提交事务!在openSession(true)方法中添加参数为true表示自动提交事务。

public class MybatisUtils {
	......
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }
}

使用注解方式,它们映射的语句可以不用 XML 来配置:只是解放了xml文件方式配置sql语句,但两种方式可以同时使用。

public interface UserMapper {
    //查询全部用户
    @Select("select * from mybatis.user")
    List<User> getUserList();
    //根据ID查询用户
    //当方法存在多个参数,所有的参数前面必须加上@Param("#")注解
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);
    //插入一个用户
    @Insert("insert into user values(#{id},#{name},#{pwd})")
    int addUser(User user);
    //修改用户
    @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);
    //删除一个用户
    @Delete("delete from user where id=#{id}")
    int deleteUser(int id);
}

其余代码不变,但是一定要在mybatis-config.xml核心配置文件中映射接口:

<configuration>
    ......
    <!--现在用注解取代了UserMapper.xml文件,就用不了resource属性绑定,只有一个接口文件,所以用class属性去绑定很合适-->
    <mappers>
        <mapper class="com.mofei.dao.UserMapper"/>
    </mappers>
</configuration>

8.4 关于@Param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议加上!
  • 在sql中引用的就是我们这里的@Param("#")中设定的属性!

9 复杂查询环境

多对一与一对多的查询要用到之前略过的图片内容中的两个属性:
在这里插入图片描述
建立两个数据库表:学生表与老师表
【多对一:多个学生关联一个老师】【一对多:一个老师集合了多个学生】
在这里插入图片描述

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

测试环境搭建:
1,新建实体类Teacher,Student
2,建立Mapper接口
3,建立Mapper.xml文件
4,在核心配置文件中绑定映射注册的Mapper接口或者文件
5,测试查询是否成功
注意点:
(1)绑定映射注册

    <!--映射注册-->
    <mappers>
        <mapper class="com.mofei.dao.StudentMapper"/>
        <mapper class="com.mofei.dao.TeacherMapper"/>
    </mappers>

(2)其余正常构建

模块目录结构如下:
在这里插入图片描述

9.1 多对一的处理

查询所有的学生信息,以及对应的老师的信息!
实体类Student

public class Student {
    private int id;
    private String name;
    //学生需要关联一个老师
    private Teacher teacher;
9.1.1 按照查询进行嵌套处理(子查询)

思路:1,查询所有的学生信息   2,根据查询出来的学生的tid字段,查找对应的老师

<mapper namespace="com.mofei.dao.StudentMapper">
    <!--
    思路:
        1,查询所有的学生信息
        2,根据查询出来的学生的tid字段,查找对应的老师    
    -->
    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--复杂的属性,需要单独处理,对象使用:association 集合使用:collection-->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    
    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id = #{tid}
    </select>
</mapper>

多个学生可关联一个老师,在实体类Student中teacher是Teacher类型的对象,使用association关联标签,其中property值为Student实体类中的属性,column为(Student实体类所多对应的)student表中的字段;javaType为实体类中对象属性所对应的对象类型

在这里插入图片描述
进行测试:

    @Test
    public void getStudentTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> student = mapper.getStudent();
        for (Student stu : student) {
            System.out.println(stu);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

9.1.2 按照结果嵌套查询(联表查询)
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname
        from student s, teacher t
        where s.tid = t.id
    </select>
    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

通过联表查询的方式也能达到相同的效果:
在这里插入图片描述

9.2 一对多的处理

一个老师管理多个学生!对于老师而言,就是一堆多的关系
实体类Teacher

public class Teacher {
    private int id;
    private String name;
    //一个老师管理多个学生
    private List<Student> student;
    ......
9.2.1 按照结果嵌套查询(联表查询)
    <!---->
    <select id="getTeacher" resultMap="TeacherStudent">
        select t.id tid,t.name tname,s.name sname,s.id sid
        from teacher t,student s
        where t.id = s.tid and tid = #{id};
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="student" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

在一对多的的情况下:集合使用:collection;且在表明集合中对象类型是用的属性为:ofType,其余结构用法与之前案例相同
进行测试:

    @Test
    public void getTeacher(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher(1);
        for (Teacher teacher1 : teacher) {
            System.out.println(teacher1);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

9.2.2 按照查询进行嵌套处理(子查询)
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from teacher where id = #{id}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="student" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherID"/>
    </resultMap>
    <select id="getStudentByTeacherID" resultType="Student">
        select * from student where tid = #{id}
    </select>

测试结果:
在这里插入图片描述

9.2.3 小结

1,关联:association【多对一】
2,集合:collection【一对多】
3,javaType  &  ofType
  (1)javaType 用来指定实体类中属性的类型
  (2)ofType用来指定映射到List或者集合中pojo类型,泛型中的约束类型
4,去了解一下内容:Mysql引擎,InnoDB,索引,索引优化

10 动态SQL

动态 SQL 是 MyBatis 的强大特性之一。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素
什么是动态SQL:动态SQL就是指根据不同条件生成不同的SQL语句
所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

10.1 搭建环境

创建数据库表:

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

在utils文件夹下建立IDutils.java,用于生成随机的id值:

public class IDutils {
    public static String getId(){
        //获得随机的id值
        return UUID.randomUUID().toString().replaceAll("-","");
    }
}

在接口中添加方法,并在配置文件中书写sql语句,用于添加数据:

    @Test
    public void addBlogTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();

        blog.setId(IDutils.getId());
        blog.setTitle("java");
        blog.setAuthor("Bruce Eckel");
        blog.setCreateTime(new Date());
        blog.setViews(1024);

        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("python");
        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("mybatis");
        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("Spring");
        mapper.addBlog(blog);

        sqlSession.close();
    }

10.2 IF

    //查询Blog
    List<Blog> queryBlogIF(Map map);
    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>

这条语句提供了可选的查找文本功能。如果不传入 “title"或者"author”,那么所有的blog都会返回;如果传入了 “title”/“author” 参数,那么就会对 “title”/“author” 一列进行模糊查找并返回对应的blog结果
进行测试:

    @Test
    public void queryBlogIFTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        map.put("title","java");
        map.put("author","Bruce Eckel");
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

10.3 choose (when, otherwise)

  有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
  还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就执行< othrewise >标签中的条件。

    //查询Blog
    List<Blog> queryBlogChoose(Map map);
    <select id="queryBlogChoose" resultType="Blog" parameterType="map">
        select * from mybatis.blog where 1=1
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
				and views = 1024
			</otherwise>
        </choose>
    </select>

进行测试:

    @Test
    public void queryBlogChooseTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        map.put("title","java");
        map.put("author","Bruce Eckel");
        List<Blog> blogs = mapper.queryBlogChoose(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

测试结果:
在这里插入图片描述

10.3 trim (where, set)

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

	//查询Blog
    List<Blog> queryBlogWhere(Map map);
    <select id="queryBlogWhere" parameterType="map" resultType="Blog">
        select * from mybatis.blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>

测试结果:
在这里插入图片描述

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

    //更新blog
    int updateBlogSet(Map map);
    <update id="updateBlogSet" parameterType="map">
        update mybatis.blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author},
            </if>
            <if test="views !=null">
                views = #{views}
            </if>
        </set>
        where id = #{id}
    </update>

进行测试:

    @Test
    public void updateBlogSetTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        map.put("title","springmvc");
        map.put("author","Bruce Eckel");
        map.put("id","235e36a513cf46ed8007d5fbc4f4fbc1");
        mapper.updateBlogSet(map);
        sqlSession.close();
    }

测试结果:
在这里插入图片描述
在这里插入图片描述
trim
在这里插入图片描述
在这里插入图片描述

10.4 sql片段

有些时候,我们可能会将一些公共部分抽取出来,方便复用。
1,使用sql标签抽取公共部分

    <sql id="IF-title-author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </sql>
    <select id="queryBlogWhere" parameterType="map" resultType="Blog">
        select * from mybatis.blog
        <where>
            <include refid="IF-title-author"></include>
        </where>
    </select>

2,在需要使用的地方使用include标签引用即可。

10.5 foreach

在这里插入图片描述
  foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示: 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
案例: 查询博客第1-2-3号记录的博客
将博客的id值更改为1,2,3,4
在这里插入图片描述

//查询博客第1-2-3号记录的博客
    List<Blog> queryBlogForeach(Map map);

完全sql表达式写法:select * from mybatis.blog where id in(1 or 2 or 3)

    <select id="queryBlogForeach" parameterType="map" resultType="Blog">
        select * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" open="(" separator="or" close=")">
                id = #{id}
            </foreach>
        </where>
    </select>

进行测试:

    @Test
    public void queryBlogForeachTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        ArrayList<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(2);
        HashMap map = new HashMap();
        map.put("ids",ids);
        mapper.queryBlogForeach(map);
        sqlSession.close();
    }

测试结果:
在这里插入图片描述
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了。
建议:先在Mysql中写出完整的SQL再对应的去修改成为我们的动态SQL实现通用。


查看官方文档:Mybatis3官方文档


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值