zoukankan      html  css  js  c++  java
  • Mybatis学习笔记

    Mybatis教程: https://blog.csdn.net/hellozpc/article/details/80878563

    sql语句的参数类型

    parameterType有简单类型(8个基本类型和String)以及对象类型。有两种获取参数值的方法

    #{字段名}:若参数类型为对象类型时,字段名必须与对象的属性名一致,若为简单类型则不用。String类型的参数会给参数值加上单引号;

    ${字段名}:若参数类型为简单类型时,必须用${value}获取参数值。${}直接替换占位符,String类型的参数不会给参数值加上单引号。sql语句动态生成的时候,使用${};

    <select id="queryUserByName" parameterType="String" reusltType="com.sa.User">
      select * from user where uname = #{name} or uname like '%${name}%'
      and address_code = #{adderss.code}
      order by ${name}
    </select>

    sql语句的返回类型

    a. resultType 

    1. 类的全路径
    <select id="queryAllUsers"  resultType="com.sa.User">
      select * from user
    </select>
    2. 使用类的别名
    在mybatis配置文件中指定别名,然后mapper中可以直接使用别名 resultType="User"
    <typeAliases> 
        <typeAlias type="com.sa.User" alias="User"/> 
    </typeAliases>

    b.resultMap

    解决实体类和表字段名称不一致问题

    autoMapping默认完成映射,需要开启驼峰匹配
    <resultMap id="userResult" type="com.sa.User" autoMapping="true">
      <id property="id" column="user_no"/>
      <result property="name" column="uname"/>
    </resultMap>
    也可以使用如下方法解决字段名称不一致的问题
    <select id="queryAllUsers"  resultType="HashMap">
      select user_no "id", uname "name" from user
    </select>

    解决实体类和表字段类型不一致问题  需要用到类型转换器

    调用存储过程

    a. 编写存储过程
    create or replace procedure procQueryCountByName (name in varchar, count out number)
    as begin
      select count(*) from user where uname = name;
    end;
    
    b. 定义Mapper接口
    int queryCountByAgeWithProc(HashMap params);
    
    c. 编写Mapper.xml sql
    存储过程的入参必须为对象类型
    <select id="queryCountByNameWithProc" statementType="CALLABLE" parameterType="HashMap">
      { CALL procQueryCountByName(
        #{name, jdbcType=VARCHAR, mode=IN},
        #{count, jdbcType=INTEGER, mode=OUT},
      )}
    </select>
    
    d. 调用接口
    Map<String, Object> params = new HashMap<>();
    params.put("name", "lily");
    userMapper.queryCountByAgeWithProc(params);
    Object count = params.get("count");  // 获取输出参数

    Mybatis动态sql

    a. Mybatis标签

    1. 使用where 1=1拼接动态sql
    <select id="queryUserByNameAndAge" parameterType="User" resultType="userResult">
      select * from user
      where 1=1
      <if test=" name!=null and name!='' ">
        and uname=#{name}
      </if>
    </select>
    
    2. 使用<where>标签,该标签会自动处理第一个<if>中的and
    <select id="queryUserByNameAndAge" parameterType="User" resultType="userResult">
      select * from user
      <where>
        <if test=" name!=null and name!='' ">
        and uname=#{name}
        </if>
      </where>
    </select>

    b. 集合处理

    入参类型为List时,在mapper.xml文件中必须使用list代替该集合。数组则用array,简单类型数组:parameterType=“int[]” ,对象类型数组:parameterType=“Object[]”

    <select id="queryUsersByIds" parameterType="java.util.List" resultType="userResult">
      select * from user where 1=1
      <if test="list!=null and list.size>0">
         and id in 
        <foreach collection="list" open="(" close=")" item="id" separator=",">
          #{id}
        </foreach>
      </if>
    </select>

    c. SQL片段

    1. 提取重复的SQL语句
    <sql id="idCondition">
      <if test="list!=null and list.size>0">
         and id in 
        <foreach collection="list" open="(" close=")" item="id" separator=",">
          #{id}
        </foreach>
      </if>
    <sql>
    2. 引用SQL片段
    <select id="queryUsersByIds" parameterType="java.util.List" resultType="userResult">
      select * from user where 1=1
      <include refid="idCondition" />
    </select>

     关联查询

    一对一关联查询

    1. 使用业务扩展类StudentBO
    Student(sno, sname, cardid), StudentCard(cardid, cardinfo),  StudentBO(sno, sname, cardid, cardinfo)
    <select id="queryStudentInfo" resultType="StudentBO">
      select s.*, c.* from student s, student_card c where s.cardid=c.cardid
    </select>
    2. 使用resultMap关联
    a. 创建关联实体类
    Student(sno, sname, StudentCard card)
    b. 定义返回类型resultMap,一对一使用association 
    <resultMap id="studentResult" type="student">
      <id property="sNo" column="sno"/>
      <result property="sName" column="sname"/>
      <association property="card" javaType="StudentCard">
        <id property="cardId" column="cardid"/>
        <result property="cardInfo" column="cardinfo"/>
      </association>
    </resultMap>
    c. SQL查询语句
    <select id="queryStudentInfo" resultMap="studentResult">
      select s.*, c.* from student s, student_card c where s.cardid=c.cardid
    </select>

    一对多关联查询

    a. 创建关联实体类
    Student(sno, sname, classid), StudentClass(classId, className, List<Student> students)
    b. 定义返回类型resultMap
    <resultMap id="studentClassResult" type="studentClass">
      <id property="classId" column="classid"/>
      <result property="className" column="classname"/>
      <!-- students属性类型javaType="List" 元素类型ofType="student" -->
      <collection property="students" ofType="student">
        <id property="sNo" column="sno"/>
        <result property="sName" column="sname"/>
      </collection>
    </resultMap>
    c. SQL查询语句
    <select id="queryStudentClassInfo" resultMap="studentResult">
      select c.*, s.* from student_class c inner join student s  on c.classid=s.classid
    </select>

    Mybatis整合日志

    1. 导入log4j.jar包,添加配置文件log4j.properties

    2. 在mybatis配置文件中开启日志, 指定使用的具体日志框架

      <settings> <setting name="logImpl" value="LOG4J"/> </settings>

    延迟加载

    1. 开启延迟加载
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/> 开启延迟加载
        <setting name="AggressiveLazyLoading" value="false"/> 关闭立即加载
    </settings>    
    2. 查询学生的sql,正常情况会查询两张表student和student_card,开启延迟加载后,只会查询student表,column是外键
    <resultMap id="lazyLoadStudentResult" type="student">
      <id property="sNo" column="sno"/>
      <result property="sName" column="sname"/>
      <association property="card" javaType="StudentCard" select="queryStudentCardById" column="cardid"/>
      </association>
    </resultMap>
    
    <select id="queryStudentInfo" resultMap="lazyLoadStudentResult">
      select s.*, c.* from student s, student_card c where s.cardid=c.cardid
    </select>
    如果是一对多的情况,查询SQL中应该只查询主表student_class,不用关联student表了
    3. 查询学生证的sql,当获取student.getCard()时,才会再次发起数据库连接执行该sql
    <select id="queryStudentCardById" parameterType="int" resultType="student">
        select * from student_card where cardid=#{cardid}
    </select>

    Mybatis缓存

    缓存类型 默认开启 缓存范围 数据存储位置 保存条件 缓存失效条件
    一级缓存 同一个SqlSession对象 内存 第一次查询之后 执行commit
    二级缓存 同一个namespace 硬盘 执行close 执行commit

     

    一级缓存
        Mybatis默认开启一级缓存,如果用同一个SqlSession对象查询相同的数据,mybatis只会在第一次查询时发起数据库查询,并将结果放入session中,后续的查询直接从缓存中取数据。当执行session.commit()(进行增删改操作)后会清理所有缓存对象,防止脏数据。
    二级缓存

    Mybatis自带二级缓存:
        Mybatis自带二级缓存,默认没有开启,同一个namespace产生的Mapper对象可以共享缓存。当执行session.close()将数据保存到二级缓存(实际上是保存到硬盘中),因此缓存的对象必须实现序列化接口。当其他session执行commit后会清理所有缓存对象,当前session只有在close后才会写入二级缓存,因此在该session执行期间不需要刷新二级缓存。
    a. 在mybatis配置文件开启二级缓存
      <setting name="cacheEnabled" value="true"/>
    b. 在Mapper.xml中指定cache语句,开启mybatis默认的二级缓存,则该namespace的sql可以进行缓存,也可以使用useCache禁用某个sql的二级缓存

    <mapper namespace="com.sa.mapper.studentMapper>
        <cache/>
        <select> ...
        <select useCache="false"> ...
    </mapper>

    如果是同一个SqlSession对象进行多次相同的查询,则直接进入一级缓存;
    如果不是同一个SqlSession对象进行多次相同的查询,但是均来自同一个namespace,则进入二级缓存

     

    SqlSession session1 = sessionFactory.open();
    StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
    Student student = mapper1.queryStudentById(2); // 将数据保存到一级缓存
    student  = mapper1 .queryStudentById(2);   // 进入一级缓存
    session1.commit();
    student  = mapper1 .queryStudentById(2);  // 执行commit后,一级缓存中的数据被清除,即缓存失效
    session1.close(); // 将数据保存到二级缓存
    SqlSession session2 = sessionFactory.open();
    StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
    student = mapper2.queryStudentById(2); // 进入二级缓存

    三方提供的二级缓存:

    要想整合三方提供的二级缓存,必须实现Mybatis的Cache接口。整合ehcache二级缓存的步骤如下:
    a. 导入Ehcache-core.jar、mybatis-Ehcache.jar、slf4j-api.jar
    b. 编写配置文件Ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
            updateCheck="false">
     
       <diskStore path="c:\ehcache"/> 
       
       <cache   name = "EhcacheDefaultCache"    
         maxElementsInMemory = "20000"    
         maxElementsOnDisk = "0"    
         eternal = "false"    
         overflowToDisk = "false"    
         diskPersistent = "false"    
         timeToIdleSeconds = "1800"    
         timeToLiveSeconds = "1800"    
         diskSpoolBufferSizeMB = "200"    
         diskExpiryThreadIntervalSeconds = "10"    
         memoryStoreEvictionPolicy = "FIFO"    
         >  
         <cacheEventListenerFactory class="com.seryo.cache.MyCacheEventListenerFactory"/>
       </cache> 
         
        <!-- 
        name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)。
        maxElementsInMemory: 在内存中缓存的element的最大数目。 
        maxElementsOnDisk: 在磁盘上缓存的element的最大数目,默认值为0,表示不限制。 
        eternal: 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。 
        overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上。
         
        以下属性是可选的: 
        timeToIdleSeconds: 对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
        timeToLiveSeconds: 对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
        diskPersistent: 是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。 
        diskExpiryThreadIntervalSeconds: 对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。 
        diskSpoolBufferSizeMB: DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。 
        memoryStoreEvictionPolicy: 如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。
         
        缓存的3 种清空策略 :
        FIFO ,first in first out (先进先出).
        LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
        LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
         -->
    </ehcache>
    ————————————————
    版权声明:本文为CSDN博主「酒丿精」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/hujiujun/article/details/81699624
    View Code

    c. 开启ehcache二级缓存

    <mapper namespace="com.sa.mapper.studentMapper>
      <cache type="org.mybatis.caches.ehcache.EhcacheCache">
         <!-- 可以覆盖Ehcache.xml中的值 -->
            <property name="maxElementsInMemory" value="2000"/>
      </cache>
    </mapper>

    逆向工程

    通过表自动生成对应的实体类和mapper接口

     步骤如下:

    a. 导入mybatis-generator-core.jar

    b. 逆向工程的配置文件generator.xm



  • 相关阅读:
    KindEditor简单的Demo使用
    动态从数据库读取菜单(ASP.NET版)
    完全卸载sql2005
    关于在xp(sp3 专业版)下安装sql2005开发版图解
    新手上路Tomcat 7.x和JDK的配置
    关于IE6幽灵字体
    【译】写个好的 CLI 程序
    【译】通过 Rust 学习解析器组合器 — Part 1
    【译】PHP 内核 — zval 基础结构
    【译】PHP 内核 — 字符串管理
  • 原文地址:https://www.cnblogs.com/anxiao/p/12283345.html
Copyright © 2011-2022 走看看