• mybatis使用-高级用法(二)


    新建学生表和学生证表

    --学生表
    CREATE TABLE student(
     id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
     `name` VARCHAR(20) NOT NULL  COMMENT '姓名',
     `age` INT NOT NULL COMMENT '年龄',
      sex INT NOT NULL COMMENT '性别 1 男 0 女',
      cid INT NOT NULL COMMENT '班级id',
      cardId INT COMMENT '学生证id'
     )
     --学生证表
     CREATE TABLE Card
     (
      id INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
      number INT NOT NULL COMMENT '学生证id',
      studentId INT NOT NULL COMMENT '学生id'
     )

    动态标签

    include&sql

     实现sql复用

    <sql id="columns">
            id,name,age
        </sql>
        <!--useCache 表示使用缓存 -->
        <select id="selectOne" parameterType="string"  flushCache="false"
            useCache="true" resultMap="studentAndClassMap">
            select <include refid="columns"/> from student
            <!--模拟if标签 -->
            <if test="id !=null and id!=''">
                where id=#{id}
            </if>
        </select>

    where&if

    <select id="selectOne" parameterType="string"  flushCache="false"
            useCache="true" resultMap="studentAndClassMap">
            select <include refid="columns"/> from student
            <where>
                <if test="id !=null and id!=''">
                   and id=#{id}
                </if>
    <if test="name !=null and name!=''">
    and name=#{name}
    </if> </where> </select>

    where标签里面有if标签成立 则自动在sql后面拼接where 同时去除多余的and

    choose, when, otherwise

    <select id="find" parameterType="map" resultType="student">
    
            select * from student  
        <!--     if else if  else -->
        <where>
            <choose>
                <when test="sex != null">
                  and sex=#{sex}
               </when>
               <when test="name != null and name != ''">
                   and name like concat('%',#{name},'%')
               </when>
            <!-- <otherwise>
               ...
            </otherwise> -->
            </choose>
        </where>
        </select>

    trim, set

    select * from user 
    
      <trim prefix="WHERE" prefixoverride="AND |OR">
    
        <if test="name != null and name.length()>0"> AND name=#{name}</if>
    
        <if test="gender != null and gender.length()>0"> AND gender=#{gender}</if>
    
      </trim>

    满足条件拼接 where 同时去掉前面多余的and或者or

     update user
    
      <trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
    
        <if test="name != null and name.length()>0"> name=#{name} , </if>
    
        <if test="gender != null and gender.length()>0"> gender=#{gender} ,  </if>
    
      </trim>

      满足条件拼接set 同时去掉后面多余的, 再拼接 suffix

     update user
    
      <set>
    
        <if test="name != null and name.length()>0"> name=#{name} , </if>
    
        <if test="gender != null and gender.length()>0"> gender=#{gender} ,  </if>
    
      </set>

    满足条件拼接set 同时去掉多余的,

    一对多级联

    1.学生mapper增加一个根据班级获取学生

    <select id="findByClassesId" parameterType="int" resultType="student">
            select * from student where cid=#{id}
        </select>
     public List<Student> findByStudent(Student params);

    2.在classes类增加一个学生集合

    public class Classes implements Serializable{
    ....
    private List<Student> students;
    }

    2.classesMapper增加自定义resultMap

    <resultMap id="classVoMap" type="com.liqiang.vo.ClassesVo">
            <id property="id" column="id" />
            <result property="name" column="name" />
            <collection property="students" column="id"
                select="com.liqiang.mapper.StudentMapper.findByClassesId"></collection>
        </resultMap>
    select为调用指定mapperStatement(可以理解是指定key的标签namespace+id)
    column 为将哪个列作为参数传递
    students 返回结果赋值的属性
    可以设置 fetchType="eager(默认值 不按层级加载)|lazy" 就是有有很多级的时候 是否一下把所有级加载出来

    3.在需要使用resultMap的地方指定resultMap 如根据id获得class

    <select id="findById" parameterType="Integer" resultMap="classVoMap">
       select *
       from classes where id=#{id}
    </select>

    多对一, 一对一级联

    1.学生表增加classes

    public class Student implements Serializable{
    .... private Classes classes;
    }

    2.学生表增加自定义resultMap

        <resultMap id="studentAndClassMap" type="student" >
            <id property="id" column="id" />
            <result property="name" column="name" />
            <result property="age" column="age" />
            <result property="cid" column="cid" />
            <association property="classes" column="cid"
                         select="com.liqiang.mapper.ClassesMapper.findById"></association>
        </resultMap>

    3.在需要级联的地方resultMap改为这个

        <!--useCache 表示使用缓存 -->
        <select id="selectOne" parameterType="string"  flushCache="false"
            useCache="true" resultMap="studentAndClassMap">
            select * from student
            <!--模拟if标签 -->
            <if test="id !=null and id!=''">
                where id=#{id}
            </if>
        </select>

    跟多对一一样 只是标签改为association

    可以通过Sesstio全局设置级联是否延迟加载

    <settings>
        <setting name="lazyLoadingEnabled" value="true"></setting><!--开启级联延迟加载-->
          <!--不按层级延迟加载  根据get 来加载   可以在collection 或者association 加上属性覆盖全局  fetchType="eager(默认值 不按层级)|lazy"-->
        <setting name="aggressiveLazyLoading" value="false"></setting>
    
      </settings>

    层级加载的意思 就是 比如学生级联班级,班级又有学校级联   当延迟加载情况getClass时是否也级联加载学校,或者非延迟加载 所有的都加载出来

    resultMap或者ParameterMap继承

    <resultMap id="studentMap" type="studentVo">
            <id property="id" column="id" />
            <result property="name" column="name" />
            <result property="age" column="age" />
            <result property="cid" column="cid" />
            
            <association property="card" column="id"
                select="com.liqiang.mapper.CardMapper.findByStudentId"></association>
        </resultMap>
        <resultMap id="studentAndClassMap" type="student" >
            <id property="id" column="id" />
            <result property="name" column="name" />
            <result property="age" column="age" />
            <result property="cid" column="cid" />
            <association property="classes" column="cid"
                         select="com.liqiang.mapper.ClassesMapper.findById"></association>
        </resultMap>

    如我定义了2个Resultmap 一个需要class级联 一个只需要学生证级联,是否发现前面几个属性几乎是copy的

    我们可以这样

    <resultMap id="simpleType" type="student">
            <id property="id" column="id" />
            <result property="name" column="name" />
            <result property="age" column="age" />
            <result property="cid" column="cid" />
    
        </resultMap>
        <resultMap id="studentMap" type="student" extends="simpleType">
    
            <association property="card" column="id"
                select="com.liqiang.mapper.CardMapper.findByStudentId"></association>
        </resultMap>
        <resultMap id="studentAndClassMap" type="student"  extends="simpleType" >
    
            <association property="classes" column="cid"
                         select="com.liqiang.mapper.ClassesMapper.findById"></association>
        </resultMap>

    使用extends="simpleType" 继承

    Mybatis对枚举支持

    1.添加一个性别枚举

    public enum SexEnum {
        MALE(1, "男"), FEMAL(0, "女");
        private int id;
        private String name;
    
        private SexEnum(int id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }

    2.将学生性别改为枚举类型

    public class Student implements Serializable{
    ....
    private SexEnum sex; }

    3.resultMap的TypeHandle处理器改为mybatis提供的枚举处理器

    <resultMap id="studentMap" type="studentVo">
                    ....
            <result property="sex" column="sex"
                typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />

    自定义TypeHandle

    实现TypeHandle接口就好了。然后像上面一样typeHandle改为自己指定的,因为mybatis默认提供个TypeHandle基本够用了。找不到例子 测试

    自定义缓存

    分布式 或者集群我们缓存都是存在redis或者其他nosql上面,redis缓存默认是存在当前服务器内存,

    这种时候我们需要自定义缓存

    public class MyCache implements org.apache.ibatis.cache.Cache{
        private String id;
        /**
         *读的时候其他线程可以读
         *读的时候其他线程不能写
         *写的时候其他线程不能写
         *写的时候不能读
         * getData(){
         *     try{
         *         readWriteLock.readLock(); 读锁
         *     }catch(execption e){
         *   
         *     }finally{
         *    readWriteLock.readLock().unlock();
         *     }
         * }
         * 
         * setData(){
         *  *     try{
         *         readWriteLock.writerLock(); 写锁
         *     }catch(execption e){
         *   
         *     }finally{
         *    readWriteLock.writerLock().unlock();
         *     }
         * }
         * 外部代理类会在get 和put 方法 加上读写锁
         */
        private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//读写锁 
        
        public MyCache(String id){
            System.out.println(id);//对应的mapper全名称标示
            this.id=id;
        }
        private static Map<Object, Object> cacheManager=new HashMap<Object, Object>();//模拟redis
        //获取缓存编号
        public String getId() {
            // TODO Auto-generated method stub
             
            return id;
        }
        //缓存数据
        public void putObject(Object key, Object value) {
            
            System.out.println("缓存对象 key为:"+key.toString());
            // TODO Auto-generated method stub
            cacheManager.put(key, value);
            
        }
       //获取缓存
        public Object getObject(Object key) {
            // TODO Auto-generated method stub
            System.out.println("获取对象 key为:"+key.toString());
            return cacheManager.get(key);
        }
       //删除缓存
        public Object removeObject(Object key) {
            return cacheManager.remove(key);
        }
        //清空缓存
        public void clear() {
            cacheManager.clear();
            
        }
        //获取缓存对象大小
        public int getSize() {
            // TODO Auto-generated method stub
            return cacheManager.size();
        }
        //获取缓存读写锁
        public ReadWriteLock getReadWriteLock() {
            // TODO Auto-generated method stub
            return readWriteLock;
        }
    
    }

    实现Cache 接口

    在需要Mapper缓存的Mapper.xml配置

    <!-- eviction 回收策略 LRU:最近最少使用 FIFO:先进先出 SOFT 软引用 WEAK 移除最长时间不使用的对象 flushInterVal:刷新时间间隔 
            毫秒。不配置 执行inser update delete 才会刷新 type :自定义缓存需要实现 org.apache.ibatis.cache.Cache -->
        <cache eviction="LRU" flushInterval="100000" size="1024"
            readOnly="true" type="com.liqiang.tool.MyCache"></cache>

    在需要更新缓存的地方

        <!--flushCache 是否刷新缓存 -->
        <update id="update" parameterType="student" flushCache="true">
            update student set name=#{name},sex=#{sex} where id=#{id}
        </update>

    打上flushCache="true"

    mybatis缓存的粒度不是很细。一刷新缓存整个表就刷新了。比如id为1的数据修改 你想只更新这个缓存,mybatis是更新整个表

  • 相关阅读:
    typedef的用法
    重定向在网络编程中的理解
    简答的理解C语言中的各种类型函数
    栈、堆、静态存储区
    标识符起作用范围----作用域、连接类型、存储期
    main函数的argc和argv
    基本数据类型
    数组与指针
    第一章 CLR的执行模型
    Revit 二次开发 沿弧形路径创建拉伸屋顶
  • 原文地址:https://www.cnblogs.com/LQBlog/p/9277490.html
Copyright © 2020-2023  润新知