MyBatis小结

既然做了SpringMVC的小结,那就顺便做个MyBatis的小结。

MyBatis和Hibernate的执行流程差不多,都是加载配置文件 - 会话工厂建造器 - 会话工厂 - 会话 - 执行具体逻辑

Configuration->SqlSessionFactoryBuilder/SessionFactoryBuilder->SqlSessionFactory/SessionFactory->SqlSession/Session

且都有懒加载、一二级缓存。

但MyBatis没有Hibernate那么抽象,学习起来相对简单。只需要从其自带的文档MyBatis-User-Guide中搞清楚几个概念即可。配置等更是可以直接从文档中复制。

和Hibernate类似,MyBatis的执行需要配置文件(Cfg文件)和映射文件(一般称为Mapper文件)。

配置文件无需多说,就是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 resource="db.properties" /><!--加载数据库信息-->
    <typeAliases>
        <package name="cn.larry.mybatis.po" /><!--类型别名,批量处理-->
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" /><!--事务管理器-->
            <dataSource type="POOLED"><!--数据源 || 连接池-->
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="cn/larry/mybatis/mapper/UserMapper.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="test">

    <!-- 需求:根据id查询用户信息 -->
    <!--    id:唯一标识。 
     parameterType:参数类型,输入映射的类型。
     resultType:返回结果类型,输出映射的类型(总是对应表中一条记录的类型)。
     #{}:占位符,如果传递的是基本类型,{}内的名称:任意。
     ${}:连接符,如果传递的是基本类型,{}内的名称:value
--> <select id="queryUserById" parameterType="int" resultType="cn.larry.mybatis.po.User"> select * from user where id = #{id} </select> <!-- 根据username查询用户信息 --> <select id="queryUserListByUsername" parameterType="string" resultType="cn.larry.mybatis.po.User"> select * from user where username like '%${value}%' </select> <!-- 根据username查询用户信息 --> <select id="queryUserList" parameterType="string" resultType="cn.larry.mybatis.po.User"> select * from user </select> <!-- 添加用户 --> <insert id="insertUser" parameterType="cn.larry.mybatis.po.User"> <selectKey keyProperty="id" resultType="int" order="AFTER"> select LAST_INSERT_ID() <!-- 插入后返回id,仅限于自增主键;select uuid()则可以返回uuid类型的主键 --> </selectKey> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert> <!-- 更改用户 --> <update id="updateUser" parameterType="cn.larry.mybatis.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update> <!-- 删除用户--> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete> </mapper>

注意上面的标签名,增删改查的操作都有对应标签(仅仅是为了更好的辨识,本质上仍然是一堆SQL语句)。

另外,有人可能不理解连接符$的含意,其实模糊查询那里已经很明显了。

占位符#是要作为查询的一个参数,独立的参数;连接符$则可以联合已有的数据然后整体作为一个参数。

你可以写成 '%${value}%',但不能写成 '%#{value}%',因为#{value}是个独立的参数,甚至无需引号。

至于标签的属性,看英文即可明白。

MyBatis的执行是直接调用映射文件中的标签id:

User selectOne = sqlSession.selectOne("cn.larry.mybatis.mapper.UserMapper.queryUserById", 1); // 1是queryUserById需要的参数

传统的Dao和DaoImpl是将SqlSessionFactory注入DaoImpl,通过接口方法调用映射文件中的标签id,但这很麻烦,而且冗余代码太多。

@Override
public User queryUserById(int id) throws Exception {
    SqlSession session = sqlSessionFactory.openSession();
    User user = session.selectOne("test.queryUserById", id);
    return user;
}

所以Mybatis提供了另一种实现方式:Mapper代理

这种方式只需要声明接口,再编写映射文件即可。

但是,它要求①接口名和映射文件名一致;②映射文件的namespace就是接口的全名称(无扩展名);③接口方法要与映射文件中的标签id一致。

<?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代理方式,只需要接口,不需要实现 -->
<!-- 1、namespace要和mapper的类全路径名称 -->
<mapper namespace="cn.larry.mybatis.mapper.UserMapper">

    <select id="queryAllUserList" resultType="user">
        SELECT * FROM USER
    </select>
    
</mapper>    
package cn.larry.mybatis.mapper;

import java.util.List;
import cn.larry.mybatis.po.User;

public interface UserMapper {
    public List<User> queryAllUserList();
}

具体调用:

UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 指定Mapper对应的类(内部是JDK动态代理
List<User> queryAllUserList = mapper.queryAllUserList();

MyBatis提供了resultMap属性,可以将查询的返回结果绑定到指定的属性上。

其他:

一对一:association。javaType。通过主键/id联合。

一对多:collection。ofType。通过主键/id联合。

多对多:由一对一、一对多嵌套联合完成。

注意,标签中使用extends="xxx_id",可以继承已有的mapper。
例如:Orders类中有User类还有OrdersDetail类,而一个mapper是查询订单和用户的数据,另一个mapper是查询Orders、User以及OrdersDetail的数据,那么后者可以继承前者,从而只需要添加对OrdersDetail的查询即可。

延迟加载,就是按需加载,本质上就是将关联的子查询延后加载(未必是外键关联的,同Hibernate)。默认关闭。
前提一:association或collection的内容可以独立出去,再使用select属性引入,column属性是关联的外键。
前提二:settings配置。<setting name="lazyLoadingEnabled" value="true"/>  (查找方法:直接查找标签对应的类,查找其中的属性)(所有标签都对应某个类)
上面是标签实现。


mybatis的缓存
一级缓存,sqlSession级别的缓存,会话级别的缓存。语句和参数都相同。如果执行了commit操作,清空缓存。一级缓存的数据结构hashmap。(数据库也有缓存)
二级缓存,mapper级别的缓存。只针对单表。重点:序列化。
一级缓存始终开启;二级缓存可以设置开启关闭。(cacheEnabled)想使用二级缓存,<cache></cache>即可。见说明。
但,由于一二级缓存都是mybatis的缓存,有局限性,所以通常在分布式架构中使用第三方缓存,如ehcache、redis、memcache等。
ehcache1.7后,为集群提供了五种解决方案,rmi、jms、ehcache server、jgroups、terracotta。rmi不存在主从。

若使用第三方缓存,缓存需要实现mybatis提供的Cache接口。加入jar包,设置配置文件,以及<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>即可。

原文地址:https://www.cnblogs.com/larryzeal/p/5336298.html