Mybatis学习笔记

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习笔记相关的知识,希望对你有一定的参考价值。

目录

1. Mybatis简介

1.1 原始JDBC操作

1.2 原始JDBC操作的分析

1.3 什么是Mybatis

2. Mybatis的快速入门

2.1 Mybatis的开发步骤

2.2 Mybatis入门

2.3 Mybatis的映射文件概述

3. Mybatis的增删改查操作

3.1 Mybatis的插入数据操作

3.1.1 示例

3.1.2 插入操作的注意事项

3.2 Mybatis的修改数据操作

3.2.1 示例

3.2.2 修改操作的注意事项

3.3 Mybatis的删除数据操作

3.3.1 示例

3.3.2 删除操作的注意事项

4. Mybatis核心配置文件概述

4.1 Mybatis核心配置文件层级关系

4.2 Mybatis常用配置解析

4.2.1 标签

4.2.2 标签

4.2.3 标签

4.2.4 标签

5. MyBatis相应API

5.1 SqlSession工厂构建器SqlSessionFactoryBuilder

5.2 SqlSession工厂对象SqlSessionFactory

5.3 SqlSession会话对象

6. Mybatis的Dao层实现

6.1 传统开发方式

6.2 代理开发方式

6.2.1 代理开发方式介绍

6.2.2 使用代理方式

7. 动态SQL

7.1 动态SQL概述

7.2 动态SQL之

7.3 动态SQL之

7.4 SQL片段抽取

8. MyBatis核心配置文件深入

8.1 标签

8.2 标签

9. Mybatis的多表操作

9.1 一对一查询

9.1.1 一对一查询的模型

9.1.2 一对一查询的语句

9.1.3 创建表所对应的实体类

9.1.4 创建Mapper接口

9.1.5 创建对应的Mapper映射文件

9.1.6 测试

9.2 一对多查询

9.2.1 一对多查询的模型

9.2.2 一对多查询的语句

9.2.3 创建实体类

9.2.4 创建对应的Mapper接口

9.2.5 配置对应的Mapper配置文件

9.2.6 测试

9.3 多对多查询

9.3.1 多对多查询的模型

9.3.2 多对多查询语句

9.3.3 创建对应的实体类

9.3.4 创建对应的Mapper接口方法

9.3.5 配置对应的Mapper配置文件

9.3.6 测试

9.4 多表查询小结

10. Mybatis注解开发

10.1 Mybatis常用注解

10.2 Mybatis单表的增删改查

10.3 Mybatis的注解实现复杂映射开发

10.3.1 一对一查询

10.3.2 一对多查询

10.3.3 多对多查询


1. Mybatis简介

1.1 原始JDBC操作

查询数据的操作代码如下:

插入数据的操作:

我们可以发现每一个方法都需要自己建立连接、关闭连接,写SQL语句,为参数赋值,封装结果集。

其实有很多操作如建立/关闭连接、为参数赋值、封装结果集都是通用的,可以考虑进行封装。

1.2 原始JDBC操作的分析

原始jdbc开发存在的问题如下:

  • ①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能。
  • ②sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变java代码(sql语句变化,就可能重新为参数赋值、重新封装结果集)
  • ③查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置。

应对上述问题给出的解决方案:

  • ①使用数据库连接池初始化连接资源(使用数据库连接池来管理连接资源)
  • ②将sql语句抽取到xml配置文件中(解耦合)
  • ③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射。

1.3 什么是Mybatis

mybatis 是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。

mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。

最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作。

2. Mybatis的快速入门

MyBatis官网地址:mybatis – MyBatis 3 | Introduction

2.1 Mybatis的开发步骤

开发步骤如下:

  • 第一步,导入Mybatis相关的依赖包或maven坐标
  • 第二步,创建数据库表,这里是创建users表
  • 第三步,编写对应的实体类,这里是创建User实体类
  • 第四步,编写实体类对应的映射文件,这里是创建UserMapper.xml
  • 第五步,编写mybatis的核心配置文件sqlMapConfig.xml
  • 第六步,进行测试

2.2 Mybatis入门

第一步,导入Mybatis相关的依赖包或maven坐标

注意:mybatis和mysql驱动包的坐标是必要的。

<!--mybatis坐标-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>
<!--mysql驱动坐标-->
<dependency>    
    <groupId>mysql</groupId>   
    <artifactId>mysql-connector-java</artifactId>    
    <version>5.1.6</version>    
    <scope>runtime</scope>
</dependency>
<!--单元测试坐标-->
<dependency>    
    <groupId>junit</groupId>    
    <artifactId>junit</artifactId>    
    <version>4.12</version>    
    <scope>test</scope>
</dependency>
<!--日志坐标-->
<dependency>    
    <groupId>log4j</groupId>    
    <artifactId>log4j</artifactId>    
    <version>1.2.12</version>
</dependency>

第二步,创建数据库表,这里是创建users表

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `password` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', '张三', '123456');
INSERT INTO `users` VALUES ('2', '李四', '654321');
INSERT INTO `users` VALUES ('3', '赵六', '987456');

第三步,编写对应的实体类,这里是创建User实体类

public class User 
    private int id;
    private String username;
    private String password;
    // getXXX()、setXXX()方法、无参构造器、全参构造器、toString()方法

第四步,编写实体类对应的映射文件,这里是创建UserMapper.xml

如果是maven项目则在resources目录下创建UserMapper.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="userMapper">
    <select id="findAll" resultType="com.demo.User">        
		select * from users    
	</select>
</mapper>

第五步,编写mybatis的核心配置文件sqlMapConfig.xml

同样在resources目录下创建sqlMapConfig.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>
    <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/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

第六步,进行测试

public class Test 
    public static void main(String[] args) throws IOException 
        // 加载核心配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 生产sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行查询sql语句
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        // 打印结果
        System.out.println(userList);
        // 关闭资源
        sqlSession.close();
    

打印结果如下:

2.3 Mybatis的映射文件概述

3. Mybatis的增删改查操作

3.1 Mybatis的插入数据操作

3.1.1 示例

第一步,编写UserMapper映射文件

<mapper namespace="userMapper">
    <insert id="insert" parameterType="com.demo.User">
	insert into users(username,password) values(#username,#password)
    </insert>
</mapper>

由于要插入参数,所以parameterType属性规定了要插入参数的类型,值是一个全类名,如果是自定义的类型如User则全类名是com.demo.User,如果是Integer类型,则也可以使用全类名。

第二步,进行测试

public class Test 
    public static void main(String[] args) throws IOException 
        // 加载核心配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 生产sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行插入
        User user = new User(1, "王五", "852147");// 这里模拟插入,手动创建一个User对象
        int result = sqlSession.insert("userMapper.insert", user);
        // 提交事务
        sqlSession.commit();
        // 关闭资源
        sqlSession.close();
    

3.1.2 插入操作的注意事项

  • 插入语句使用<insert>标签
  • 在映射文件中使用parameterType属性指定要插入的数据类型,属性值是数据类型的全类名,如果是自定义的数据类型如User则全类名是com.demo.User,如果是Java的数据类型也可以使用全类名,但还可以使用别名,如Integer的别名就是integer。
  • Sql语句中使用#实体属性名方式引用实体中的属性值
  • 插入操作使用的API是sqlSession.insert(“命名空间.id”, 实体对象);
  • 插入操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()

3.2 Mybatis的修改数据操作

3.2.1 示例

第一步,编写UserMapper映射文件

<mapper namespace="userMapper">
    <update id="update" parameterType="com.demo.User">
	update users set username=#username,password=#password where id=#id
    </update>
</mapper>

第二步,进行测试

public class Test 
    public static void main(String[] args) throws IOException 
        // 加载核心配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 生产sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行更新
        User user = new User(1, "王五", "852147");// 这里模拟插入,手动创建一个User对象
        int result = sqlSession.update("userMapper.update", user);
        // 提交事务
        sqlSession.commit();
        // 关闭资源
        sqlSession.close();
    

3.2.2 修改操作的注意事项

  • 修改语句使用<update>标签

  • 修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);

  • 更新操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()

3.3 Mybatis的删除数据操作

3.3.1 示例

第一步,编写UserMapper.xml文件

<mapper namespace="userMapper">
    <delete id="delete" parameterType="java.lang.Integer">
	delete from users where id=#id
    </delete>
</mapper>

第二步,测试

public class Test 
    public static void main(String[] args) throws IOException 
        // 加载核心配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 生产sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行删除
        int result = sqlSession.delete("userMapper.delete", 1);
        // 提交事务
        sqlSession.commit();
        // 关闭资源
        sqlSession.close();
    

3.3.2 删除操作的注意事项

  • 删除语句使用<delete>标签

  • Sql语句中使用#任意字符串方式引用传递的单个参数

  • 删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

  • 删除操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()

4. Mybatis核心配置文件概述

4.1 Mybatis核心配置文件层级关系

4.2 Mybatis常用配置解析

下面是sqlMapConfig.xml文件中的配置说明:

4.2.1 <environments>标签

<environment>标签是数据库的环境配置标签,支持多环境配置。

注意,<environments>标签中的default属性的值是<environment>标签的id属性值是相关的,如果配置多个<environment>标签,那么<environments>标签的default属性值则是指定一个<environment>的id,如果只配置一个<environment>标签,那么default属性和id属性一一对应。

其中<transactionManager>标签是配置事务管理器的,type的值有两种情况:

  • JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。 通常使用这个。
  • MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。

其中<dataSource>标签配置数据源,type的值有三种情况:

  • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
  • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。 通常使用这个。
  • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

在<dataSource>标签下配置的是数据源的连接参数,使用<property>标签来进行配置,name属性值就是这几个固定的参数名,value属性的值是连接参数。

4.2.2 <mapper>标签

<mapper>标签是包在<mappers>下的,可以写多个<ampper>标签来加载多个映射。

<mappe>标签是用来加载映射的,加载方式有如下几种:

  • 使用相对于类路径的资源引用,例如:
<mapper resource="com/demo/mapper/UserMapper.xml"/>
  • 使用完全限定资源定位符(URL),例如:
<mapper url="file:///com/demo/mapper/UserMapper.xml"/>
  • 使用映射器接口实现类的完全限定类名,例如:
<mapper class="com.demo.mapper.UserMapper"/>
  • 将包内的映射器接口实现全部注册为映射器,例如:
<package name="com.demo.mapper"/>

4.2.3 <properties>标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root

4.2.4 <typeAliases>标签

该标签可以为全类名设置别名。

类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下 :

配置<typeAliases>标签后,为"com.demo.User"定义一个别名"user",再看:

注意:<typeAliases>标签是包裹<typeAlias>子标签的,<typeAlias>标签才是设置别名的,type属性就是你实际上的全类名,而alias属性就是要设置的别名。

上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名

除了上面这种设置具体某个类的别名的方式之外,下面还可以设置多个类的别名的方式:

mybatis就会扫描这个包里的类,然后自动注册成一个type alias,如果没有用Alias注解指定名字,就会自动命名,使用类的全小写名。

<typeAliases>
    <package name="com.demo.bean"/>
</typeAliases>

5. MyBatis相应API

5.1 SqlSession工厂构建器SqlSessionFactoryBuilder

常用API:SqlSessionFactory build(InputStream inputStream)

通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

// 加载核心配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获取SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 生产sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();

其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。

5.2 SqlSession工厂对象SqlSessionFactory

SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:

5.3 SqlSession会话对象

SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。

执行语句的方法主要有:

// 查询一个对象
<T> T selectOne(String statement, Object parameter) 
// 查询多条记录
<E> List<E> selectList(String statement, Object parameter) 
// 插入操作
int insert(String statement, Object parameter) 
// 更新操作
int update(String statement, Object parameter) 
// 删除操作
int delete(String statement, Object parameter)

操作事务的方法主要有:

// 提交事务
void commit()
// 回滚事务  
void rollback() 

6. Mybatis的Dao层实现

6.1 传统开发方式

第一步,编写UserDao接口

public interface UserDao 
    List<User> findAll() throws IOException;

第二步,编写UserDaoImpl实现

public class UserDaoImpl implements UserDao 
    public List<User> findAll() throws IOException 
        // 加载SqlMapConfig.xml配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象        
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        // 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行查询
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        // 关闭连接
        sqlSession.close();
        // 返回查询结果
        return userList;
    

第三步,测试传统方式

@Test
public void testTraditionDao() throws IOException 
    UserDao userDao = new UserDaoImpl();
    List<User> all = userDao.findAll();
    System.out.println(all);

6.2 代理开发方式

6.2.1 代理开发方式介绍

采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。

Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper 接口开发需要遵循以下规范:

  • 1) Mapper.xml文件中的namespace与mapper接口的全限定名相同
  • 2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  • 3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
  • 4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

6.2.2 使用代理方式

第一步,编写UserMapper接口并且设置<mapper>标签的namespace属性值的值变成了对应接口的全类名

第二步,不需要像传统方式那样,写接口实现类,所以直接写测试类

@Test
public void testProxyDao() throws IOException 
    // 加载SqlMapConfig.xml配置文件
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 创建SqlSessionFactory工厂对象    
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    // 获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获得MyBatis框架生成的UserMapper接口的实现类,getMapper()方法的参数是接口类
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 直接调用方法名进行查询
    User user = userMapper.findById(1);
    // 打印查询结果
    System.out.println(user);
    // 关闭连接
    sqlSession.close();

注意,如果使用的是传统方式,那么在IDEA中UserMapper.xml的id属性值会是红色的,但这不是报错。

当namespace中使用对应的接口路径后,那么下面的id属性不会变红。

注意,如果安装了某些mybatis插件后,那么对应的<select>标签的旁边就会有一个箭头直接跳到对应的接口方法中。

7. 动态SQL

7.1 动态SQL概述

Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。

7.2 动态SQL之<if>

我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。

<select id="findByCondition" parameterType="user" resultType="user">
    select * from User
    <where>
        <if test="id!=0">
            and id=#id
        </if>
        <if test="username!=null">
            and username=#username
        </if>
    </where>
</select>

注意,<where>标签可以根据<if>标签是否被用到来决定是否有where这个关键字,也可以相当于"where 1=1"那么一定正确。

当查询条件id和username都存在时,控制台打印的sql语句如下 :

当查询条件只有id存在时,控制台打印的sql语句如下:

7.3 动态SQL之<foreach>

循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。

<mapper namespace="com.demo.UserMapper">
    <select id="findByIds" parameterType="list" resultType="user">
        select * from users
        <where>
            <foreach collection="list" open="id in (" item="id" separator="," close=")">
                #id
            </foreach>
        </where>
    </select>
</mapper>

测试代码的情况如下

其中open属性值和close属性值都是拼接的字符串,而item属性值是#id的中的名称,separator属性值是分隔符,这里用逗号作为分隔符。

<foreach>标签用于遍历集合,它的属性:

  • collection:代表要遍历的集合元素,一般写"collection"或"list"
  • open:代表语句的开始部分
  • close:代表结束部分
  • item:代表遍历集合的每个元素,生成的变量名
  • sperator:代表分隔符

7.4 SQL片段抽取

Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。

使用<sql>标签抽取sql语句,其中id属性表示抽取的这个sql的唯一标识,<sql></sql>标签内就是抽取的sql语句。

然后通过<include>标签进行引用,其中refid属性值就是<sql>标签的id值,进行对应。

例如:

未进行SQL抽取的代码如下:

<mapper namespace="com.demo.UserMapper">
    <select id="findById" parameterType="int" resultType="user">
        select * from users where id=#id
    </select>
    <select id="findByIds" parameterType="list" resultType="user">
        select * from users
        <where>
            <foreach collection="list" open="id in (" item="id" separator="," close=")">
                #id
            </foreach>
        </where>
    </select>
</mapper>

进行SQL抽取后的代码:

<mapper namespace="com.demo.UserMapper">
    <sql id="selectAll">select * from users</sql>
    <select id="findById" parameterType="int" resultType="user">
        <include refid="selectAll"/> where id=#id
    </select>
    <select id="findByIds" parameterType="list" resultType="user">
        <include refid="selectAll"/>
        <where>
            <foreach collection="list" open="id in (" item="id" separator="," close=")">
                #id
            </foreach>
        </where>
    </select>
</mapper>

8. MyBatis核心配置文件深入

在sqlMapConfig.xml中还可以进行更深入的配置。

8.1 <typeHandlers>标签

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。

开发步骤如下:

第一步,定义转换类继承BaseTypeHandler<T>

第二步,覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法

public class MyDateTypeHandler extends BaseTypeHandler<Date> 
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType type) throws SQLException 
        // 将日期转换成毫秒变成字符串进行存储
        preparedStatement.setString(i, date.getTime() + "");
    

    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException 
        // 将毫秒取出再转换成Date类型
        return new Date(resultSet.getLong(s));
    

    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException 
        return new Date(resultSet.getLong(i));
    

    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException 
        return callableStatement.getDate(i);
    

第三步,在MyBatis核心配置文件中进行注册

<!--注册类型自定义转换器-->
<typeHandlers>
    <typeHandler handler="com.demo.MyDateTypeHandler"></typeHandler>
</typeHandlers>

第四步,进行测试

执行添加操作

查询结果

8.2 <plugins>标签

MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据。

开发步骤:

第一步,导入插件PageHelper的坐标

<!-- 分页助手 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
</dependency>
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>0.9.1</version>
</dependency>

第二步,在mybatis的核心配置文件sqlMapConfig.xml文件中配置PageHelper插件

    <!-- 注意:分页助手的插件,配置在通用mapper之前 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 指定方言 -->
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>

第三步,测试分页插件的功能

只需要在查询开始之前加上一句PageHelper.startPage(pageNum,pageSize);即可。

public class Test 
    public static void main(String[] args) throws IOException 
        // 加载核心配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 获取SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 生产sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 执行查询
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        // 查询所有,进行分页,页码从1开始
        Page page = PageHelper.startPage(1, 2);
        List<User> userList = mapper.findAll();
        for (User user : userList) 
            System.out.println(user);
        
        // 关闭资源
        sqlSession.close();
    

获取分页相关的其他参数:

//其他分页的数据
PageInfo<User> pageInfo = new PageInfo<User>(select);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());

9. Mybatis的多表操作

所谓的多表操作通常指多表查询,至少是两张表及以上的查询。

9.1 一对一查询

9.1.1 一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。又比如一个用户可以发布多篇博客,但一篇博客只会对应一个用户。

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户。

建表SQL如下:

-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ordertime` datetime NOT NULL,
  `total` double NOT NULL,
  `uid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('1', '2021-05-19 20:47:14', '756', '1');
INSERT INTO `orders` VALUES ('2', '2021-05-12 20:47:30', '147', '1');
INSERT INTO `orders` VALUES ('3', '2021-05-13 20:47:40', '369', '2');
INSERT INTO `orders` VALUES ('4', '2021-05-15 20:47:51', '123', '3');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(50) NOT NULL,
  `birthday` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '张三', '123456', '2021-03-10 20:46:18');
INSERT INTO `user` VALUES ('2', '李四', '654321', '2021-04-14 20:46:48');
INSERT INTO `user` VALUES ('3', '王五', '852357', '2021-06-26 20:47:03');

9.1.2 一对一查询的语句

查询的SQL语句如下:

select * from orders,user where orders.uid=`user`.id;

9.1.3 创建表所对应的实体类

这里是user表和orders表,所以创建对应的实体类。

User.java

public class User 
    private int id;
    private String username;
    private String password;
    private Date birthday;
    // get、set、构造器、toString等方法

Order.java

public class Order 
    private int id;
    private Date ordertime;
    private double total;
    // 代表当前订单属于哪一个客户
    private User user;
    // get、set、构造器、toString等方法

9.1.4 创建Mapper接口

为Order类创建对应的OrderMapper接口类

public interface OrderMapper 
    List<Order> findAll();

9.1.5 创建对应的Mapper映射文件

为OrderMapper借口创建对应的OrderMapper.xml文件

<mapper namespace="com.test.mapper.OrderMapper">
    <resultMap id="orderMap" type="com.test.Order">
        <result column="id" property="user.id"/>
        <result column="username" property="user.username"/>
        <result column="password" property="user.password"/>
        <result column="birthday" property="user.birthday"/>
    </resultMap>

    <select id="findAll" resultMap="orderMap">
        select * from orders,user where orders.uid=`user`.id
    </select>
</mapper>

注意,需要在sqlMapConfig.xml文件中进行配置

除了上面这种方式外,<resultMap>标签还可以这样配置,也能起到相同的作用:

    <resultMap id="orderMap" type="com.test.Order">
        <result property="id" column=&#

以上是关于Mybatis学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis学习笔记11:解决字段名和属性的映射关系

Mybatis学习笔记导航

MyBatis笔记

springmvc+mybatis学习笔记(汇总)

mybatis学习笔记(14)-spring和mybatis整合

mybatis学习笔记(14)-mybatis整合ehcache