Java框架--MyBatis

Java框架--MyBatis

简化数据库操作的持久层框架

中文手册:

https://mybatis.org/mybatis-3/zh/index.html

https://mybatis.net.cn/

Maven仓库:

https://mvnrepository.com/

工作示意图

快速入门

代码参考gitee仓库,其中使用maven两个功能:继承父工程环境、创建配置资源拷贝

日志输出

日志文档:

https://mybatis.org/mybatis-3/zh/logging.html

配置日志:

https://mybatis.org/mybatis-3/zh/configuration.html#settings

框架核心原理图

  • mybatis的核心配置文件
    • mybatis-config.xml:进行全局配置,全局只能有一个这样的配置文件
    • XxxMapper.xml配置多个SQL,可以有多个XxxMappe.xml配置文件
  • 通过mybatis-config.xml配置文件得到SqlSessionFactory
  • 通过SqlSessionFactory得到SqlSession,用SqlSession就可以操作数据了
  • SqlSession底层是Executor(执行器),有2重要的实现类,有很多方法
  • MappedStatement是通过XxxMapper.xml中定义,生成的statement对象
  • 参数输入执行并输出结果集,无需手动判断参数类型和参数下标位置,且自动将结果集映射为Java对象

原生的API&注解的方式

原生API,直接使用API来操作数据(其实就是把底层的api直接使用,该配置的xml、接口也还是需要配置)

//=============add==================
sqlSession.insert("com.hspedu.mapper.MonsterMapper.addMonster",monster);

//=============del==================
sqlSession.delete("com.hspedu.mapper.MonsterMapper.delMonster",3);

//=============update==================
sqlSession.update("com.hspedu.mapper.MonsterMapper.updateMonster",monster);

注解的方式,可不再使用MonsterMapper.xml(但是仍需要在mybatis-config.xml注册含注解的类),但其实不推荐此方式,没有解耦

// 注册xml(原来)
<mapper resource="com.hspedu.mapper.MonsterMapper.xml"/>
// 注册注解类
<mapper class="com.hspedu.mapper.MonsterAnnotation"/>

注解类代码参考gitee仓库

配置文件

mybatis的核心配置文件(mybatis-config.xml),实现配置jdbc连接信息,注册mapper

文档地址:

https://mybatis.org/mybatis-3/zh/configuration.html

  • settings全局参数定义
  • typeAliases别名处理器
  • typeHandlers类型处理器(Mybatis的映射基本已经满足,不太需要重新定义)
  • environments环境
    • 注册mapper: xml文件、注解类、url:外部路径(使用很少,不推荐)、package方式注册(当一个包下有很多的Mapper.xml文件和基于注解实现的接口时为了方便,我们可以以包方式进行注册)

映射文件

XxxxMapper.xml-SQL映射文件

文档地址:

https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

常用的顶级元素:

按照应被定义的顺序列出

  • cache–该命名空间的缓存配置。

  • cache-ref–引用其它命名空间的缓存配置。

  • resultMap–描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。

  • parameterType-将会传入这条语句的参数的类全限定名或别名

  • sql–可被其它语句引用的可重用语句块。

  • insert–映射插入语句。

  • update–映射更新语句。

  • delete–映射删除语句。

  • select–映射查询语句。

动态SQL语句

处理更复杂的查询业务需求

文档地址:

https://mybatis.org/mybatis-3/zh/dynamic-sql.html

常用标签

1.if[判断]

2.where[拼接where子句]

3.choose/when/otherwise[类似java的switch语句,注意是单分支]

4.foreach[类似in]

5.trim[替换关键字/定制元素的功能

6.set[在update的set中,可以保证进入set标签的属性被修改,而没有进入set的,保持原来的值]

使用案例代码请参考gitee仓库

映射关系1对1

关键代码(相互引用时注意sout输出代码会造成栈溢出)

		//不推荐,使用联合查询
		<resultMap id="PersonResultMap" type="Person">
        <!--<result property="id" column="id"/>-->
        <!--id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
            1.property="id" 表示person 属性 id ,通常是主键
            2.column="id" 表示对应表的字段
        -->
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--association – 一个复杂类型的关联
        1. property="card" 表示 Person对象的 card 属性
        2. javaType="IdenCard" 表示card 属性 的类型
        3. column="id" 是从我们的 下面这个语句查询后返回的字段
        SELECT *  FROM `person`,`idencard` WHERE `person`.id=1
        AND `person`.card_id = `idencard`.id
        -->
        <association property="card" javaType="IdenCard">
            <result property="id" column="id"/>
            <result property="card_sn" column="card_sn"/>
        </association>
    </resultMap>
    <select id="getPersonById" parameterType="Integer"
            resultMap="PersonResultMap">
        SELECT *  FROM `person`,`idencard` WHERE `person`.id = #{id}
        AND `person`.card_id = `idencard`.id
    </select>
================================================================================
		//推荐方式,使用嵌套其他select方法
		<resultMap id="PersonResultMap2" type="Person">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--
        1. mybatis第二种方式核心思想: 将这个多表联查,分解成单表操作 , 这样简洁,而且易于维护 ,推荐
        2. 而且可以复用你已经写好的方法 -组合
        3. property="card": 表示 Person对象的 card 属性
        4. column="card_id" 这个是
        SELECT * FROM `person` WHERE `id` = #{id}  返回的 字段 card_id 信息/数据
        5. 返回的 字段 card_id 信息/数据 作为getIdenCardById入参, 来执行
        -->

        <association property="card" column="card_id"
                     select="com.hspedu.mapper.IdenCardMapper.getIdenCardById" />
    </resultMap>
    <select id="getPersonById2" parameterType="Integer" resultMap="PersonResultMap2">
        SELECT * FROM `person` WHERE `id` = #{id}
    </select>

映射关系1对多

关键代码(相互引用时注意sout输出代码会造成栈溢出)

    <resultMap id="UserResultMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--解读:因为pets属性是集合,因此这里需要是collection标签来处理
        1. ofType="Pet" 指定返回的集合中存放的数据类型Pet
        2. collection 表示 pets 是一个集合
        3. property="pets" 是返回的user对象的属性 pets
        4. column="id" SELECT * FROM `mybatis_user` WHERE `id` = #{id} 返回的id字段对应的值
        -->
        <collection property="pets" column="id" ofType="Pet"
                    select="com.hspedu.mapper.PetMapper.getPetByUserId"/>
    </resultMap>
    <select id="getUserById" parameterType="Integer" resultMap="UserResultMap">
        SELECT * FROM `mybatis_user` WHERE `id` = #{id}
    </select>

缓存

  • 机制的目的是提高检索效率

  • 缓存执行顺序:二级缓存 -> 一级缓存 -> DB数据库

  • 不会出现二级缓存和一级缓存有重复数据的情况,因为二级是一级关闭后才有的数据

一级缓存

会话级别缓存,默认开启,当你重复查询相同内容时,不会再发出sql请求

存储的位置:SqlSession.executor.delegate.localCache.cache(HashMap类型)

失效分析:

  • 关闭SqlSession会话(sqlSession.close() 调用后),此时如果配置二级缓存,一级缓存数据会放入到二级缓存
  • 执行sqlSession.clearCache() 清除缓存
  • 当同一个缓存对象被修改,该对象在一级缓存中会失效

二级缓存

全局级别缓存,针对不同会话都有效,会在日志中输出命中率:二级缓存返回数据次数/获取数据次数

开关使用:

  • settings全局参数定义 开启 cacheEnabled(默认true开启)
  • entity类实现序列号接口(serialize),因二级缓存可能使用序列号技术(看具体使用的技术)
  • 在对应的XxxMapper.xml中设置二级缓存策略则开启:eviction回收策略、flushInterval时间间隔、size引用数目、readOnly只读优化(这样配置是Mybatis自带缓存产品)
  • 对应的XxxMapper.xml中对应方法标签属性useCache(默认true开启)

EhCache-第三方缓存产品

纯Java的缓存框架,具有快速、精干等特点,可以利用Mybatis二级缓存的接口接入Mybatis框架使用

配置文档:https://www.cnblogs.com/zqyanywn/p/10861103.html

细节说明(Java Ehcache缓存的timeToIdleSeconds和timeToLiveSeconds区别):https://www.taobye.com/f/view-11-23.html

使用:

  • 导入核心jar包

        <dependencies>
    		<!--核心库-->
            <dependency>
                <groupId>net.sf.ehcache</groupId>
                <artifactId>ehcache-core</artifactId>
                <version>2.6.11</version>
            </dependency>
    		<!--引入需要使用的slf4j-->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.25</version>
            </dependency>
    		<!--引入mybatis整合ehcache库/jar-->
            <dependency>
                <groupId>org.mybatis.caches</groupId>
                <artifactId>mybatis-ehcache</artifactId>
                <version>1.2.1</version>
            </dependency>
    
        </dependencies>
    
  • 配置相关缓存

    mybatis-config.xml
    <settings>
        <!--默认开启,这里显式的配置-->
    	<setting name="cacheEnabled" value="true"/>
    </settings>
    
    XxxMapper.xml
    注意如果原来有配置二级缓存,记得注销原来的cache配置
    <cache type="org.mybatis.caches.ehcache.EncacheCache"/>
    
  • 加入ehcache配置文件,放入资源文件夹(运行时的类路径)--固定文件名--ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache>
        <!--
           diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
           user.home – 用户主目录
           user.dir  – 用户当前工作目录
           java.io.tmpdir – 默认临时文件路径
         -->
        <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
        <!--
           defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
         -->
        <!--
          name:缓存名称。
          maxElementsInMemory:缓存最大数目
          maxElementsOnDisk:硬盘最大缓存个数。
          eternal:对象是否永久有效,一但设置了,timeout将不起作用。
          overflowToDisk:是否保存到磁盘,当系统当机时
          timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
          timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
          diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
          diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
          diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
          memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
          clearOnFlush:内存数量最大时是否清除。
          memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
          FIFO,first in first out,这个是大家最熟的,先进先出。
          LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
          LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
       -->
        <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="259200"
                memoryStoreEvictionPolicy="LRU"/>
    </ehcache>
    
posted @   邵泽龙  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示