MyBatis(一)MyBatis初识

MyBatis 目录

MyBatis介绍

转载自:http://c.biancheng.net/mybatis

​ MyBatis 是一款的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

​ MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

mybatis/mybatis-3: MyBatis SQL mapper framework for Java (github.com)

安装MyBatis

引入依赖

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

当然引入MyBatis之前还需要引入驱动,这里使用mysql驱动 当前版本 8.0.27

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>x.x.x</version>
</dependency>

在这个地址查看版本Releases · mybatis/mybatis-3 (github.com)

当前版本是3.5.8

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.8</version>
</dependency>

sql语句

在开始之前先在数据库中执行以下内容

CREATE DATABASE IF NOT EXISTS `jdbc_test`;

DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `blog_title` varchar(20),
  `desc` varchar(300),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into blog(`blog_title`,`desc`) values ("博客名称","博客描述");
insert into blog(`blog_title`,`desc`) values ("博客名称1","博客描述1");

MyBatis核心对象

MyBatis 有三个基本要素:

  • 核心接口和类
  • MyBatis核心配置文件(mybatis-config.xml)
  • SQL映射文件(mapper.xml)

下面首先介绍 MyBatis 的核心接口和类,如下所示。

​ 每个 MyBatis 应用程序都以一个 SqlSessionFactory 对象的实例为核心。

​ 首先获取 SqlSessionFactoryBuilder 对象,可以根据 XML 配置文件或者 Configuration 类的实例构建该对象。

​ 然后获取 SqlSessionFactory 对象,该对象实例可以通过 SqlSessionFactoryBuilder 对象来获取。

​ 有了SqlSessionFactory对象之后,就可以进而获取SqlSession实例。SqlSession 对象中完全包含以数据库为背景的所有执行 SQL 操作的方法,用该实例可以直接执行已映射的 SQL 语句。

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 会根据配置信息或者代码生成 SqlSessionFactory,并且提供了多个 build() 方法重载。

通过源码分析,可以发现以上方法都是在调用同一签名方法,即:

build(Reader reader, String environment, Properties properties)

由于参数 environment 和 properties 都可以为 null,去除重复的方法,真正的重载方法其实只有如下三种:

  • build(InputStream inputStream, String environment, Properties properties)
  • build(Reader reader, String environment, Properties properties)
  • build(Configuration config)

​ 通过上述分析,发现配置信息可以以三种形式提供给 SqlSessionFactoryBuilder build() 方法,分别是 InputStream(字节流)、Reader(字符流)、Configuration(类)。

​ 由于字节流和字符流都属于读取配置文件的方式,所以就很容易想到构建一个 SqlSessionFactory 有两种方式,即:读取 XML 配置文件和编写代码。一般习惯为采取 XML 配置文件的方式来构造 SqlSessionFactory,这样一方面可以避免硬编码,另一方面方便日后配置人员修改,避免重复编译代码。

SqlSessionFactoryBuilder的生命周期和作用域

SqlSessionFactoryBuilder 的最大特点就是用过即丢。创建 SqlSessionFactory 对象之后,这个类就不存在了,因此 SqlSessionFactoryBuilder 的最佳范围就是存在于方法体内,也就是局部变量。

SqlSessionFactory

SqlSessionFactory 是工厂接口而不是现实类,他的任务就是创建 SqlSession

所有的 MyBatis 应用都以 SqlSessionFactory 实例为中心,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 对象来获取。有了它以后,顾名思义,就可以通过 SqlSession 提供的 openSession() 方法来获取 SqlSession 实例。源码如下。

public interface SqlSessionFactory {
    SqlSession openSession();
    SqlSession openSession(boolean autoCommit);
    SqlSession openSession(Connection connection);
    SqlSession openSession(TransactionIsolationLevel level);
    SqlSession openSession(ExecutorType execType);
    SqlSession openSession(ExecutorType execType, boolean autoCommit);
    SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
    SqlSession openSession(ExecutorType execType, Connection connection);
    Configuration getConfiguration();
}

SqlSessionFactory的生命周期和作用域

SqlSessionFactory 对象一旦创建,就会在整个应用程序过程中始终存在。没有理由去销毁或再创建它,并且在应用程序运行中也不建议多次创建 SqlSessionFactory。因此 SqlSessionFactory 的最佳作用域是 Application,即随着应用程序的生命周期一直存在。这种“存在于整个应用运行期间,并且只存在一个对象实例”的模式就是所谓的单例模式(指在运行期间有且仅有一个实例)。

SqlSession

SqlSession 是用于执行持久化操作的对象,类似于 JDBC 中的 Connection。它提供了面向数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例直接运行已映射的 SQL 语句。

void clearCache();
Configuration getConfiguration();
void rollback(boolean force);
void commit(boolean force);
int delete(String statement, Object parameter);
...

SqlSession 的用途主要有两种。

  1. 获取映射器。让映射器通过命名空间和方法名称找到对应的 SQL,并发送给数据库,执行后返回结果。
  2. 直接通过“命名空间(namespace)+SQL id”的方式执行 SQL,不需要获取映射器。这是 iBatis 版本留下的方式。

SqlSession生命周期和作用域

SqlSession 对应一次数据库会话。由于数据库会话不是永久的,因此 SqlSession 的生命周期也不是永久的,每次访问数据库时都需要创建 SqlSession 对象。

需要注意的是:每个线程都有自己的 SqlSession 实例,SqlSession 实例不能被共享,也不是线程安全的。因此 SqlSession 的作用域范围是 request 作用域或方法体作用域内。

MyBatis配置文件(mybatis-config.xml)

MyBatis 配置文件的结构如下。

<?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><!-- 配置 -->
    <properties /><!-- 属性 -->
    <settings /><!-- 设置 -->
    <typeAliases /><!-- 类型命名 -->
    <typeHandlers /><!-- 类型处理器 -->
    <objectFactory /><!-- 对象工厂 -->
    <plugins /><!-- 插件 -->
    <environments><!-- 配置环境 -->
        <environment><!-- 环境变量 -->
            <transactionManager /><!-- 事务管理器 -->
            <dataSource /><!-- 数据源 -->
        </environment>
    </environments>
    <databaseIdProvider /><!-- 数据库厂商标识 -->
    <mappers /><!-- 映射器 -->
</configuration>

mybatis-config.xml 文件中的元素节点是有一定顺序的,节点位置必须按以上位置排序,否则会编译错误。

下面介绍 XML 配置文件中的重要元素(标签)。

configuration 元素是整个 XML 配置文件的根节点,其角色就相当于是 MyBatis 的总管,MyBatis 所有的配置信息都会存放在它里面。

properties标签

properties 标签可以通过 resource 属性指定外部 properties 文件(database.properties),也可以通过 properties 子元素配置。

1. 指定文件

使用 properties 指定外部文件,代码如下。

<properties resource="mybatisDemo/resources/database.properties"/>

database.properties 用于描述数据库连接的相关配置,例如数据库驱动、连接数据库的 url、数据库用户名、数据库密码等。

2. properties子元素配置

通过 properties 子元素 property 配置 usernamepassword变量,然后在 environments 节点中引用这些变量,代码如下。

<properties>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</properties>

在 environments 节点中引用 username 和 password 变量。

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

也可以不使用 properties 标签,直接将属性值写在 value 中。

settings标签

settings 标签用于配置 MyBatis 的运行时行为,它能深刻的影响 MyBatis 的底层运行,一般不需要大量配置,大部分情况下使用其默认值即可。

settings 的配置项很多,但是真正用到的不会太多,我们把常用的配置项研究清楚就可以了。settings 配置项说明如下表所示

配置项 作用 配置选项 默认值
cacheEnabled 该配置影响所有映射器中配置缓存的全局开关 true|false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态 true|false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 true|false 版本3.4.1 (不包含) 之前默认值为 true,之后为 false
multipleResultSetsEnabled 是否允许单一语句返回多结果集(需要兼容驱动) true|false true
useColumnLabel 使用列标签代替列名。不同的驱动会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果 true|false true
useGeneratedKeys 允许JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true,则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby) true|false false
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射。 PARTIAL 表示只会自动映射,没有定义嵌套结果集和映射结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套) NONE、PARTIAL、FULL PARTIAL
autoMappingUnkno wnColumnBehavior 指定自动映射当中未知列(或未知属性类型)时的行为。 默认是不处理,只有当日志级别达到 WARN 级别或者以下,才会显示相关日志,如果处理失败会抛出 SqlSessionException 异常 NONE、WARNING、FAILING NONE
defaultExecutorType 配置默认的执行器。SIMPLE 是普通的执行器;REUSE 会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新 SIMPLE、REUSE、BATCH SIMPLE
defaultStatementTimeout 设置超时时间,它决定驱动等待数据库响应的秒数 任何正整数 Not Set (null)
defaultFetchSize 设置数据库驱动程序默认返回的条数限制,此参数可以重新设置 任何正整数 Not Set (null)
safeRowBoundsEnabled 允许在嵌套语句中使用分页(RowBounds)。如果允许,设置 false true|false false
safeResultHandlerEnabled 允许在嵌套语句中使用分页(ResultHandler)。如果允许,设置false true|false true
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射 true|false false
localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速联复嵌套査询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlScssion 的不同调用将不会共享数据 SESSION|STATEMENT SESSION
jdbcTypeForNull 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER NULL、VARCHAR、OTHER OTHER
lazyLoadTriggerMethods 指定哪个对象的方法触发一次延迟加载 equals、clone、hashCode、toString
defaultScriptingLanguage 指定动态 SQL 生成的默认语言 org.apache.ibatis .script.ing.xmltags .XMLDynamicLanguageDriver
callSettersOnNulls 指定当结果集中值为 null 时,是否调用映射对象的 setter(map 对象时为 put)方法,这对于 Map.kcySet() 依赖或 null 值初始化时是有用的。注意,基本类型(int、boolean 等)不能设置成 null true|false false
logPrefix 指定 MyBatis 增加到日志名称的前缀 任何字符串 Not set
loglmpl 指定 MyBatis 所用日志的具体实现,未指定时将自动査找 SLF4J|LOG4J|LOG4J2|JDK_LOGGING |COMMONS_LOGGING |ST DOUT_LOGGING|NO_LOGGING Not set
proxyFactory 指定 MyBatis 创建具有延迟加栽能力的对象所用到的代理工具 CGLIB|JAVASSIST JAVASSIST (MyBatis 版本为 3.3 及以上的)
vfsImpl 指定 VFS 的实现类 提供 VFS 类的全限定名,如果存在多个,可以使用逗号分隔 Not set
useActualParamName 允许用方法参数中声明的实际名称引用参数。要使用此功能,项目必须被编译为 Java 8 参数的选择。(从版本 3.4.1 开始可以使用) true|false true

下面给出一个全量的配置样例,如下所示。

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="25"/>
    <setting name="defaultFetchSize" value="100"/>
    <setting name="safeRowBoundsEnabled" value="false"/>
    <setting name="mapUnderscoreToCamelCase" value="false"/>
    <setting name="localCacheScope" value="SESSION"/>
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

typeAliases标签

为了不在任何地方都指定类的全限定名,我们可以使用 typeAliases 标签定义一个别名。

例如,在 net.bianchengbang.po 包中有一个 Student 类,则该类的全限定名称为 net.bianchengbang.po.Student。使用 typeAliases标签定义别名,这样就不用每次都书写类的全限定名称了,代码如下。

<typeAliases>
    <typeAlias alias = "Student" type = "net.bianchengbang.po.Student"/>
</typeAliases>

如果需要对同一个包下的多个类定义别名,则可以定义为:

<typeAliases>
    <package name="net.biancheng.po"/>
</typeAliases>

这样 MyBatis 将扫描 net.biancheng.po 包里面的类,将其第一个字母变为小写作为其别名,例如 Student 别名为 studentUser 别名为 user

typeHandlers标签

typeHandlers 主要将获取的值合理地转化为Java类型。在 typeHandler 中,分为 jdbcTypejavaType,其中 jdbcType 用于定义数据库类型,而javaType用于定义 Java 类型,typeHandler 的作用就是承担 jdbcType javaType 之间的相互转换。

MyBatis 支持自定义处理类型,在自定义处理类型时,需要实现 org.apache.ibatis.type.TypeHandler 接口或继承 org.apache.ibatis.type.BaseTypeHandle 类。详细可参考官网:http://www.mybatis.org/mybatis-3/zh/configuration.html#typeHandlers

environments标签

environments 标签中,可以配置 MyBatis 的多套运行环境,将 SQL 映射到多个不同的数据库上。

environmentenvironments 的子标签,用来配置 MyBatis 的一套运行环境,需指定运行环境 ID、事务管理、数据源配置等相关信息。

我们可以通过配置多个environment标签来连接多个数据库,需要注意的是必须指定其中一个为默认运行环境(通过default指定)。

environment 标签提供了两个子标签,即transactionManager dataSource

transactionManager标签

MyBatis 支持两个事务管理器,即 JDBC 和 MANAGED。

如果使用 JDBC 类型的事务管理器,则应用程序服务器负责事务管理操作,例如提交、回滚等。如果使用 MANAGED 类型的事务管理器,则应用程序服务器负责管理连接生命周期。

dataSource标签

用于配置数据库的连接属性,例如要连接的数据库的驱动程序名称、URL、用户名和密码等。

dataSource 中的 type 属性用于指定数据源类型,有以下 3 种类型。

1)UNPOOLED

UNPOOLED 没有数据库连接池,效率低下。MyBatis 需要打开和关闭每个数据库操作的连接,它有点慢,通常应用于简单的应用程序。

2)POOLED

对于 POOLED 数据源类型,MyBatis 将维护一个数据库连接池。并且对于每个数据库的操作,MyBatis 都会使用连接池中的连接,并在操作完成后将它们返回到池中。减少了创建新连接所需的初始连接和身份验证时间。

3)JNDI

对于 JNDI 的数据源类型,MyBatis 将从 JNDI 数据源中获取连接。

dataSource 标签示例代码如下:

<dataSource type="POOLED">
    <!-- MySQL数据库驱动 -->
    <property name="driver" value="com.mysql.jdbc.Driver" />
    <!-- 连接数据库的URL -->
    <property name="url"
        value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8" />
    <property name="username" value="root" />
    <property name="password" value="root" />
</dataSource>

mappers标签

mappers 标签用于指定 MyBatis SQL 映射文件的路径。

mappermappers 的子标签,mapper 中的 resource 属性用于指定 SQL 映射文件的路径(类资源路径)

例如,SQL 映射文件的名称是 BlogMapper.xml,它位于名为 mapper 的包中,那么您可以这样配置:

<mappers>
    <mapper resource="mapper/BlogMapper.xml"/>
</mappers>

MyBatis Mapper(映射器)

​ 映射器是 MyBatis 中最重要的文件,文件中包含一组 SQL 语句(例如查询、添加、删除、修改),这些语句称为映射语句或映射 SQL 语句。

映射器由 Java 接口和 XML 文件(或注解)共同组成,它的作用如下。

  • 定义参数类型
  • 配置缓存
  • 提供 SQL 语句和动态 SQL
  • 定义查询结果和 POJO 的映射关系

映射器有以下两种实现方式。

  • 通过 XML 文件方式实现,比如我们在 mybatis-config.xml 文件中描述的 XML 文件,用来生成 mapper。
  • 通过注解的方式实现,使用 Configuration 对象注册 Mapper 接口。

​ 如果 SQL 语句存在动态 SQL 或者比较复杂,使用注解写在 Java 文件里可读性差,且增加了维护的成本。所以一般建议使用 XML 文件配置的方式,避免重复编写 SQL 语句。

XML实现映射器

XML 定义映射器分为两个部分:接口和XML。

定义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="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
         <id property="id" column="id" />
        <result property="blogTitle" column="blog_title"/>
        <result property="desc" column="desc"/>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

下面对上述 XML 文件进行讲解。

  • namespace 用来定义命名空间,该命名空间和定义接口的全限定名一致。
  • <select> 元素表明这是一条查询语句,属性 id 用来标识这条 SQL。resultType 表示返回的是一个 Website 类型的值。

定义接口

package org.mybatis.example;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BlogMapper {
    Blog selectBlog(int id);
}

添加配置

在 MyBatis 配置文件中添加以下代码。

<mapper resource="mapper/BlogMapper.xml" />

该语句用来引入 XML 文件,MyBatis 会读取 BlogMapper.xml 文件,生成映射器。

注解实现映射器

使用注解的方式实现映射器,只需要在接口中使用 Java 注解,注入 SQL 即可。

package org.mybatis.example;

public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

如果实体和数据库字段不一样需要进行映射

package org.mybatis.example;

import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

public interface BlogMapper {
    @Select(value = "select * from blog where id=#{id}")
    @Results(value = {
            @Result(property = "blogTitle",column = "blog_title")
    })
    public Blog selectBlog(int id);
}

这里我们使用了 @Select 注解,并且注入了和 XML 中相同的 select 语句。

如果使用注解和 XML 文件两种方式同时定义,那么 XML 方式将覆盖掉注解方式。

虽然这里注解的方式看起来比 XML 简单,但是现实中我们遇到的 SQL 会比该例子复杂得多。如果 SQL 语句中有多个表的关联、多个查询条件、级联、条件分支等,显然这条 SQL 就会复杂的多,所以并不建议读者使用这种方式。比如下面这条 SQL。

select * from t_user u
left join t_user_role ur on u.id = ur.user_id
left join t_role r on ur.role_id = r.id
left join t_user_info ui on u.id = ui.user_id
left join t_female_health fh on u.id = fh.user_id
left join t_male_health mh on u.id = mh.user_id
where u.user_name like concat('%', ${userName},'%')
and r.role_name like concat('%', ${roleName},'%')
and u.sex = 1
and ui.head_image is not null;

​ 如果把以上 SQL 放到 @Select注解中,无疑会大大降低代码的可读性。如果同时还要考虑使用动态 SQL 或需要加入其他的逻辑,这样就使得这个注解更加复杂了,不利于日后的维护和修改。

此外,XML 可以相互引入,而注解是不可以的,所以在一些比较复杂的场景下,使用 XML 方式会更加灵活和方便。因此大部分的企业都以 XML 为主,本教程也会保持一致,以 XML 方式来创建映射器。当然在一些简单的表和应用中使用注解方式也会比较简单。

这个接口可以在 XML 中定义,将在 mybatis-config.xml 中配置 XML 的语句修改为以下语句即可。

<mapper resource="com/mybatis/mapper/BlogMapper" />

也可以使用 configuration 对象注册这个接口,比如:

configuration.addMapper(BlogMapper.class);

示例

Blog

package org.mybatis.example;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Blog {
    private int id;
    private String blogTitle;
    private String desc;
}

BlogMapper

package org.mybatis.example;

import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

public interface BlogMapper {
    @Select(value = "select * from blog where id=#{id}")
    @Results(value = {
            @Result(property = "blogTitle",column = "blog_title")
    })
    public Blog selectBlog(int id);
}

MainApplication

package org.mybatis.example;

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;

public class MainApplication {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            try (SqlSession session = sqlSessionFactory.openSession()) {
                session.getConfiguration().addMapper(BlogMapper.class);
                BlogMapper mapper = session.getMapper(BlogMapper.class);
                // 你的应用逻辑代码
                Blog blog = mapper.selectBlog(1);
                System.out.println(blog.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

MyBatis 映射器的主要元素

下面介绍在映射器中可以定义哪些元素,以及它们的作用。

元素名称 描述 备注
mapper 映射文件的根节点,只有 namescape 一个属性 namescape 作用如下:用于区分不同的 mapper,全局唯一绑定DAO接口,即面向接口编程。当 namescape 绑定某一接口后,可以不用写该接口的实现类,MyBatis 会通过接口的完整限定名查找到对应的 mapper 配置来执行 SQL 语句。因此 namescape 的命名必须要跟接口同名。
select 查询语句,最常用、最复杂的元素之一 可以自定义参数,返回结果集等
insert 插入语句 执行后返回一个整数,代表插入的条数
update 更新语句 执行后返回一个整数,代表更新的条数
delete 删除语句 执行后返回一个整数,代表删除的条数
parameterMap 定义参数映射关系 即将被删除的元素,不建议使用
sql 允许定义一部分的 SQL,然后在各个地方引用它 例如,一张表列名,我们可以一次定义,在多个 SQL 语句中使用
resultMap 用来描述数据库结果集与对象的对应关系,它是最复杂、最强大的元素 提供映射规则
cache 配置给定命名空间的缓存 -
cache-ref 其它命名空间缓存配置的引用 -

后面文章中会详细介绍以上元素。

拓展

关于 MyBatis 的 SQL 映射文件中的 mapper 元素的 namescape 属性有如下要求。

  • namescape 的命名必须跟某个 DAO 接口同名,同属于 DAO 层,因此代码结构上,映射文件与该接口应放置在同一 package 下(如 org.mybatis.example.blog),并且习惯上是以 Mapper 结尾(如 BlogMapper.javaBlogMapper.xml)。
  • 不同的 mapper 文件中子元素的id可以相同,MyBatis 通过 namescape 和子元素的 id 联合区分。接口中的方法与映射文件中的 SQL 语句 id 应一 一对应。

构建SqlSessionFactory

从 XML 中构建 SqlSessionFactory

​ 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

​ 从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流InputStream实例,比如用文件路径字符串或 file://URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

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>
  <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>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

​ 当然,还有很多可以在 XML 文件中配置的选项,上面的示例仅罗列了最关键的部分。 注意 XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。

示例

使用IDEA创建Maven项目

引入依赖

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.8</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

resources文件夹下创建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/BlogMapper.xml"/>
    </mappers>
</configuration>

BlogMapper.xml

resources/mapper文件夹下创建BlogMapper.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="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
         <id property="id" column="id" />
        <result property="blogTitle" column="blog_title"/>
        <result property="desc" column="desc"/>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

以下所有文件在org.mybatis.example包下

MainApplication.java

package org.mybatis.example;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MainApplication {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Blog.java

package org.mybatis.example;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class Blog {
    private int id;
    private String blogTitle;
    private String desc;
}

BlogMapper.java

package org.mybatis.example;

import org.apache.ibatis.annotations.Mapper;

public interface BlogMapper {
    Blog selectBlog(int id);
}
	

如果一直Could not find resource mapper/BlogMapper.xml请检查BlogMapper.xml是否在resources/mapper目录下

检查BlogMapper.xml名称是否正确。如果你安装了MyBatisX文件名称不对也会有小鸟的标准。

包括但不限于这种没有后缀的名称BlogMapper

建议XML文件不要写在java目录中

不使用 XML 构建 SqlSessionFactory

​ 如果你更愿意直接从 Java 代码而不是 XML 文件中创建配置,或者想要创建你自己的配置建造器,MyBatis 也提供了完整的配置类,提供了所有与 XML 文件等价的配置项。

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

​ 注意该例中,configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射注解从而避免依赖 XML 文件。不过,由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它(在这个例子中,基于类路径和 BlogMapper.class 的类名,会加载 BlogMapper.xml)。

从 SqlSessionFactory 中获取 SqlSession

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置:

package org.mybatis.example;

public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

示例

package org.mybatis.example;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;

public class MainApplication {
    public static void main(String[] args) {
            //创建连接池
            DataSource dataSource = new PooledDataSource("com.mysql.cj.jdbc.Driver", "jdbc:mysql://localhost:3306/jdbc_test?characterEncoding=utf8", "root", "123456");
            //事务
            TransactionFactory transactionFactory = new JdbcTransactionFactory();
            //创建环境
            Environment environment = new Environment("development", transactionFactory, dataSource);
            // 创建配置
            Configuration configuration = new Configuration(environment);
            // 加入资源(Mapper接口)
            configuration.addMapper(BlogMapper.class);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
            SqlSession session = sqlSessionFactory.openSession();
            try {
                //statement:sql唯一标识(mapper.xml映射文件中的id标识)
                //parament:参数
                // 你的应用逻辑代码
                Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog",1);
                System.out.println(blog.toString());
                //操作数据时,需要有提交操作
                session.commit();
            } finally {
                session.close();
            }
    }
}

​ 该例中,configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射语句的注解从而避免依赖 XML 文件。不过,由于 Java 注解的一些限制以及某些 MyBatis 映射的复杂性,要使用大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置。有鉴于此,如果存在一个同名 XML 配置文件,MyBatis 会自动查找并加载它(在这个例子中,基于类路径和 BlogMapper.class 的类名,会加载 BlogMapper.xml)。

此处必须要把BlogMapper.class 和 BlogMapper.xml 放在同一个目录下,因为在源码中写死了读同一路径xml。

org.mybatis.example包下创建BlogMapper.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="org.mybatis.example.BlogMapper">
    <resultMap id="blogMap" type="org.mybatis.example.Blog">
         <id property="id" column="id" />
        <result property="blogTitle" column="blog_title"/>
        <result property="desc" column="desc"/>
    </resultMap>
    <select id="selectBlog" resultType="org.mybatis.example.Blog">
        select * from Blog where id = #{id}
    </select>
</mapper>

若出现一下错误说明xml没有编译

Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for org.mybatis.example.BlogMapper.selectBlog

在pom.xml文件中加入

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

刷新maven

posted @ 2021-12-17 16:34  青杉  阅读(322)  评论(0编辑  收藏  举报