• 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"/>即可。

  • 相关阅读:
    JavaWeb学习之什么是Servlet、如何使用servlet、为什么这样使用、servlet的虚拟路径、关于缺省Servlet(2)
    Android Drawable
    Android 热补丁和热修复
    Android Immersive Mode (沉浸模式) 还是 Translucent Bars (透明状态栏)
    Android & iOS 第三方 Crash ANR 捕捉上传
    Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
    Android Volley
    Android HttpURLConnection And HttpClient
    Android Fragment 生命周期及其正确使用(建议使用自定义View替换Fragment)
    Android Intent (可通过URL启动 Activity)
  • 原文地址:https://www.cnblogs.com/larryzeal/p/5336298.html
Copyright © 2020-2023  润新知