跳转至

MyBatis

1 概述

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

ORM: 对象关系映射(Object Relation Mapping)

  • object: java中的实体内对象
  • mapping:object和relation之间的映射
  • relation: 数据库中的表

orm 模型

ORM模型可以用传统JDBC实现,但是传统JDBC程序有以下设计缺陷:

  • 大量配置信息硬编码:将数据库位置、密码等保存在代码中,违反软件开发的OCP原则
  • 大量的无关业务处理的编码:数据库连接的打开和关闭,sql语句的建立和发送
  • 扩展优化极为不便:数据库连接池

其适合于:

  • 更加关注SQL优化的项目
  • 需求频繁更新改动的项目

mybatis_framework

2 核心组件

MyBatis的核心组件分为四部分:

  • SqlSessionFactoryBuilder: 生成SqlSessionFactory,采用Builder模式
  • SqlSessionFactory(工厂接口): 生成SqlSession,采用工厂模式
  • SqlSession(会话):是一个既可以发送SQL执行返回结果,也可以获取Mapper的接口。一般会让其在业务逻辑代码中消失,而是用的是Mybatis提供的SQL Mapper接口编程技术
  • SQL Mapper(映射器):负责发送SQL去执行,并返回结果

MyBatis的核心组件

SqlSessionFactoryBuilder

SqlSessionFactory SqlSessionFactory = null;

映射器

映射器由一个接口和对应的XML文件组成,可以配置以下内容:

  • 描述映射规则
  • 提供SQL语句,并可以配置SQL参数类型、返回类型、缓存刷新等信息
  • 配置缓存
  • 提供动态SQL

3 MyBatis配置

MyBatis配置文件并不复杂,它所有的元素如下:

<configuration> <!--配置-->
    <properties/> <!--属性-->
    <settings/>  <!--设置-->
    <typeAliases/> <!--类型命名-->
    <typeHandlers/> <!--类型处理器-->
    <objectFactory/> <!--对象工厂-->
    <plugins/> <!--插件-->
    <environments> <!--配置环境 -->
        <environment> <!--环境变量-->
            <transactionManager/> <!--事务管理器-->
            <dataSource/> <!--数据源-->
        </environment>
    </environments>
</configuration>

properties属性

properties属性可以给系统配置一些运行参数,可以放在XML文件或者properties文件中,而不是放在Java编码中,可以方便参数修改,而不会引起代码的重新编译。可以使用propery子元素或者properties文件的形式使用properties。

properties子元素

<properties>
    <property name="database.driver" value="com.mysql.jdbc.Driver"/>
    <property name="database.url" value="jdbc:mysql://localhost:3306/ssm/>"
</properties>

使用properties文件是比较普遍的方法,其文件就是多个键值对。在MyBatis配置文件中通过的属性resource来引入properties文件。

properties文件

database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/ssm
<properties resource="jdbc.properties"/>

typeAliases别名

由于类的全限定名称很长,需要大量使用的时候,总写那么长的名称不方便。在MyBatis中允许定义一个简写来代表这个类,这就是别名,别名分为系统定义别名和自定义别名。注意,在MyBatis中别名不区分大小写。

系统定义别名

别名 Java类型
_long long
_int int
_double double
string String
long Long
date Date

使用配置文件可以自定义别名。扫描别名时,MyBatis将扫描这个包里面的类,将其第一个字母变为小谢作为其别名。

自定义别名

<typeAliases>
    <typeAliase alias="role" type="com.exercise.ssm.Role"/>
</typeAliases>
<typeAliases>
    <typeAliase alias="role" type="com.exercise.ssm"/>
</typeAliases>

typeHandler类型转换器

typeHandler的作用就是承担jdbcType和javaType之间的相互转换,其中jdbcTpe用于定义数据库类型,javaType用户定义Java类型。在很多情况下我们并不需要去配置typeHandler、jdbcType、javaType,因为MyBatis会探测应该使用什么类型的typeHandler进行处理。

environments

在MyBatis中,运行环境主要的作用就是配置数据库信息。分为两个可配置的元素:事务管理器(transactionManager)、数据源(dataSource)。

MyBatis为Transaction提供了两个实现类:JdbcTransactionManagedTransaction。它们都实现了Transaction接口,主要工作就是提交、回滚、关闭数据库。

<transactionManager type="JDBC">
<transactionManger type="Managed">

transaction

environment的主要作用是配置数据库,在Mybatis中数据库通过PooledDataSourceFactoryUnpooledDataSourceFactoryJndiDataSourceFactory三个工厂类来提供。分别配置如下

<dataSource type="UNPOOLEd">
<dataSource type="POOLED">
<dataSource type="JNDI">
  • UNPOOLED:非数据库池的管理方式,每次请求都会打开一个新的数据库连接,创建会比较慢
  • POOLED: 数据库池的管理方式,请求时无需再建立和验证,省去了创建新的连接实例时所必需的初始化和认证时间;并且控制最大连接数,避免过多的连接导致系统瓶颈。
  • JNDI:略

引入映射器的方法

引入映射器的方法很多:

<mappers>
    <mapper resource="com/exercise/mybatis/RoleMapper.xml">
</mappers>
<mappers>
    <package name="com.exercise.mybatis">
</mappers>
<mappers>
    <mapper class="com.exercise.mybatis.RoleMapper"/>
    <mapper class="com.exercise.mybatis.UserMapper"/>
</mappers>

案例

下面的一个简单的案例演示了MyBatis的基本操作。

public class Main {

    @Test
    public void testMyBatis() throws Exception {
        SqlSessionFactory sqlSessionFactory = null;
        InputStream inputStream;

        inputStream = Resources.getResourceAsStream("mybatis.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
        Role role = roleMapper.getRole(1L);
        System.out.println(role.getId()); //1
        roleMapper.deleteRole(1L);

        Role newRole = new Role("baby", "Q");
        roleMapper.insertRole(newRole);
        Long id = newRole.getId();

        System.out.println(id); //1
        System.out.println(roleMapper.getRole(id));
        roleMapper.updateRoleInfo(id, "zhenhua", "lala");
        System.out.println(roleMapper.getRole(id));
    }
}
public class Role {
    private Long id;
    private String roleName;
    private String note;

    public Role(String roleName, String note) {
        this.roleName = roleName;
        this.note = note;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }


    @Override
    public String toString() {
        return roleName + "  id: " + id + "  note: " + note;
    }
}
//映射器接口
public interface RoleMapper {
    public Role getRole(Long id);
    public void deleteRole(Long id);
    public int getRoleNumber();
    public void updateRole(Role role);
    public void insertRole(Role role);
}
<?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>
    <typeAliases>
        <typeAlias alias="role" type="com.exercise.mybatis.example.Role"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/chapter3"/>
                <property name="username" value="root"/>
                <property name="password" value="imLarry!"/>
            </dataSource>

        </environment>
    </environments>
    <mappers>
        <mapper resource="com/exercise/mybatis/example/RoleMapper.xml"/>
    </mappers>
</configuration>
<?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="com.exercise.mybatis.example.RoleMapper">
    <select id="getRole" parameterType="long" resultType="role">
        select id, role_name as roleName, note
        from t_role
        where id = #{id}
    </select>
    <select id="deleteRole" parameterType="long">
        delete from t_role where id = #{id};
    </select>

    <select id="getRoleNumber" resultType="int">
        select count(*) from t_role;
    </select>

    <update id="updateRole" parameterType="role">
        update t_role set role_name=#{roleName} where id=#{id};
    </update>

    <insert id="insertRole" parameterType="role" useGeneratedKeys="true" keyProperty="id">
        insert into t_role (role_name, note) values(#{roleName}, #{note});
    </insert>

    <update id="updateRoleInfo">
        update t_role set role_name=#{roleName}, note=#{note} where id=#{id};
    </update>
</mapper>

4 映射器

映射器是MyBatis最复杂且最重要的组件。它由一个接口加上XML文件(或者注解)组成。在映射器中可以配置参数、SQL语句、存储过程、缓存、级联等复杂的内容,并且通过简易的映射规则映射到指定的POJO或者其他对象上,映射器能够有效消除JDBC底层的代码。

映射器的配置元素

元素名称 描述 备注
select 查询语句,最常用、最复杂的元素之一 可以自定义参数,返回结果集等
insert 插入语句 执行后返回一个整数,代表插入的条数
update 更新语句 执行后返回一个整数,代表更新的条数
delete 删除语句 执行后返回一个整数,代表删除的条数
resultMap 用来描述从数据库结果集中加载对象 它将提供映射规则
cache 给定命名空间的缓存配置 -
cache-ref 其他命名空间缓存配置的引用。 -

传递多个参数

现实的需求中,可能会有多个参数,比如订单可以根据订单名称、日期或者价格进行查询。为此, MyBatis为开发者提供了一个注解@Param(org.apache.ibatis.annotations.Param)。可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性。

传递多个参数

RoleMapper中,使用传递id,roleName来更新Role。注意此时并不需要parameterType参数,MyBatis会自动探索。

public void updateRoleInfo(@Param("id") Long id, @Param("roleName")     
        String roleName, @Param("note") String note);
<update id="updateRoleInfo">
    update t_role set role_name=#{roleName}, note=#{note} 
    where id=#{id};
</update>

主键回填

如果MySQL中的表格采用了自增主键(primary key auto_increment),MYSQL数据库会为该记录生成对应的主键。MyBatis提供了这样的支持。在insert语句中有一个开关属性useGeneratedKeys用来控制是否获取数据库生成的主键。当打开了这个开关,还要配置其属性keyProperty,告诉系统把生成的主键放在哪个属性中。

主键回填

 <insert id="insertRole" parameterType="role" useGeneratedKeys="true" keyProperty="id">
    insert into t_role (role_name, note) values(#{roleName}, #{note});
</insert>

自动映射和驼峰映射

MyBatis提供了自动映射功能,默认是开启的。如果编写的SQL列名和属性名保持一致,就会形成自动映射。

自动映射

例如通过角色编号(id)获取角色的信息:

<select id="getRole" parameterType="long" resultType="role">
    select id, role_name as roleName, note from t_role where id = #{id}
</select>

原来的列名role_name被别名roleName代替了,这样就和POJO上的属性名称保持一致了。此时MyBatis就会将这个结果集映射到POJO的属性roleName上,自动完成映射,而无需再进行任何配置。

MyBatis会严格按照驼峰命名的方式做自动映射。如果需要更为强大的映射规则,则需要考虑使用resultMap。

resultMap元素

为了支持复杂的映射,MyBatis提供了resultMap属性。

使用resultMap

下面这个例子不使用自动映射,而是使用了resultMap作为resultType。

<resultMap id="roleMap" type="role">
    <id property="id" column="id"/>
    <result property="roleName" column="role_name"/>
    <result property="note" column="note"/>
</result>
<select id="getRole" parameterType="long" resultType="roleMap">
    select id, role_name, note from t_role where id = #{id}
</select>

分页

MyBatis中可以使用RowBounds进行分页。

public List<Role> findByRowBounds(@Param("roleName") String roleName, 
    @Param("note") String note, RowBounds rowBounds);
<select id="findRowBounds" resultType="role">
    select id, role_name as roleName, note from t_role
    where role_name like
    concat('%', #{roleName}, '%')
    and note like concat('%', #{note}, '%')
</select>

级联

缓存

存储过程