美文网首页
Mybatis 知识

Mybatis 知识

作者: 十二找十三 | 来源:发表于2022-05-31 14:52 被阅读0次

基础

传参:
    1. 传 map  直接用key就行 
    2. 传 实体类对象  直接用属性
    3. @Param绑定
    4. param1 param2 param3
    5. 传单属性  _parameter

${}和#{}的区别是什么:
    #{}是预编译处理,${}是字符串替换。 使用#{}可以有效的防止SQL注入,提高系统安全性。

返回主键问题: useGeneratedKeys="true" keyProperty="id" <selectKey>处理不带自增的数据库

批量插入问题 foreach标签  jdbc: "allowMultiQueries=true"的作用:
                1.可以在sql语句后携带分号,实现多语句执行。
                2.可以执行批处理,同时发出多个SQL语句
            <insert id="insertUserList" parameterType="java.util.List" >
                 insert into bc_sys_user_pwd_help (user_id, user_pwd) values
                <foreach collection="list" item="item" separator=",">
                    (#{item.ext1}, #{item.ext3})
                </foreach>
          </insert>

一对一 多对一 一对多 多对多 association vs collection

------------------------------------------------------association-------------------------------------------------

CREATE TABLE `test_table_1` (
  `col_1` varchar(32) DEFAULT NULL COMMENT '测试列1',
  `col_2` varchar(32) DEFAULT NULL COMMENT '测试列2',
  `col_3` varchar(32) DEFAULT NULL COMMENT '测试列3',
  `col_4` varchar(32) DEFAULT NULL COMMENT '测试列4',
  `col_5` varchar(32) DEFAULT NULL COMMENT '测试列5'
);
insert into test_table_1 (col_1, col_2, col_3, col_4, col_5) values ("1", "2", "a", "b", "c");
insert into test_table_1 (col_1, col_2, col_3, col_4, col_5) values ("2", "3", "a", "b", "c");

CREATE TABLE `test_table_2` (
  `col_1` varchar(32) DEFAULT NULL COMMENT '测试列1',
  `col_2` varchar(32) DEFAULT NULL COMMENT '测试列2',
  `col_3` varchar(32) DEFAULT NULL COMMENT '测试列3',
  `col_4` varchar(32) DEFAULT NULL COMMENT '测试列4',
  `col_5` varchar(32) DEFAULT NULL COMMENT '测试列5'
);
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("2", "1", "a", "b", "c");
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("3", "2", "a", "b", "c");

// 第一种方式:直接进行关联查询 把关联实体的属性在xml中配置 然后关联查出来
<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
    <result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
    <result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
    <result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
    <association property="pro6" javaType="com.ccbckj.model.DTO2"> // column=""属性无意义 也可以单独定义 resultMap="DTO2ResultMap"
        <result column="t2_col1" property="dto2_pro1" jdbcType="VARCHAR"/>
        <result column="t2_col2" property="dto2_pro2" jdbcType="VARCHAR"/>
        <result column="t2_col3" property="dto2_pro3" jdbcType="VARCHAR"/>
    </association>
</resultMap>


<select id="test" resultMap="ResultMap">
    select
        t1.col_1 as t1_col1,
        t1.col_2 as t1_col2,
        t1.col_3 as t1_col3,
        t2.col_1 as t2_col1,
        t2.col_2 as t2_col2,
        t2.col_3 as t2_col3
    from test_table_1 t1
    inner join test_table_2 t2 on t1.col_2 = t2.col_1
</select>

// 第二种方式: 单独抽离子查询语句
<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
    <result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
    <result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
    <result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
    <association property="pro6" column="t1_col2"  javaType="com.ccbckj.model.DTO2" select="selectDto2ByCol2"></association>
    <!-- column="{aaa=t1_col1,bbb=t1_col2}" 多条件示例-->
</resultMap>

<resultMap id="DTO2ResultMap" type="com.ccbckj.model.DTO2">
    <result column="col_1" property="dto2_pro1" jdbcType="VARCHAR"/>
    <result column="col_2" property="dto2_pro2" jdbcType="VARCHAR"/>
    <result column="col_3" property="dto2_pro3" jdbcType="VARCHAR"/>
</resultMap>

<select id="selectDto2ByCol2" resultMap="DTO2ResultMap" parameterType="map">
    select
        col_1,
        col_2,
        col_3
    from  test_table_2 where col_1 = #{t1_col2}
</select>

<select id="test4" resultMap="ResultMap">
    select
        t1.col_1 as t1_col1,
        t1.col_2 as t1_col2,
        t1.col_3 as t1_col3
    from test_table_1 t1
</select>

-----------------------------------------------------collection---------------------------------------------------------
可以再次添加数据用于测试
insert into test_table_2 (col_1, col_2, col_3, col_4, col_5) values ("3", "2", "a", "b", "c");
collection 基本跟 association 类似

<resultMap id="ResultMap" type="com.ccbckj.model.DTO1">
    <result column="t1_col1" property="pro1" jdbcType="VARCHAR"/>
    <result column="t1_col2" property="pro2" jdbcType="VARCHAR"/>
    <result column="t1_col3" property="pro3" jdbcType="VARCHAR"/>
    <collection property="pro6" column="t1_col2"  javaType="java.util.List" ofType="com.ccbckj.model.DTO2" select="selectDto2CollectionByCol2"></collection>
</resultMap>

<resultMap id="DTO2ResultMap" type="com.ccbckj.model.DTO2">
    <result column="col_1" property="dto2_pro1" jdbcType="VARCHAR"/>
    <result column="col_2" property="dto2_pro2" jdbcType="VARCHAR"/>
    <result column="col_3" property="dto2_pro3" jdbcType="VARCHAR"/>
</resultMap>

<select id="selectDto2CollectionByCol2" resultMap="DTO2ResultMap" parameterType="map">
    select
        col_1,
        col_2,
        col_3
    from  test_table_2 where col_1 = #{t1_col2}
</select>

<select id="test4" resultMap="ResultMap">
    select
        t1.col_1 as t1_col1,
        t1.col_2 as t1_col2,
        t1.col_3 as t1_col3
    from test_table_1 t1
</select>

Mybatis的延时加载问题

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载

局部延时加载功能
association collection标签中用 fetchType="lazy"
fetchType="lazy" 懒加载策略
fetchType="eager" 立即加载策略

全局加载配置
#全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。
mybatis.configuration.lazy-loading-enabled=true
#当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
mybatis.configuration.aggressive-lazy-loading=false

lazyLoadingEnabled(lazy-loading-enabled)默认为 false, 也就是不使用懒加载. 所以如果 association 和 collection 使用了 select, 那么 MyBatis 会一次性执行所有的查询. 如果 accociation 和 collection 中的 fetchType 指定为 lazy, 那么即使 lazyLoadingEnabled 为 false, MyBatis 也会使用懒加载  Java 配置中 @One 和 @Many 的 fetchType 支持三个值: LAZY, EAGER, DEFAULT, 其中 DEFAULT 的意思是跟随全局设置即 lazyLoadingEnabled
aggressiveLazyLoading(aggressive-lazy-loading)默认为 true, 也就是说当你开启了懒加载之后, 只要调用返回的对象中的任何一个方法, 那么 MyBatis 就会加载所有的懒加载的属性, 即执行你配置的 select 语句

延迟加载的加载触发方法lazyLoadTriggerMethods默认值为 equals,clone,hashCode,toString, 当你调用这几个方法时, MyBatis 会加载所有懒加载的属性

MyBatis延迟加载主要使用:JavassistProxyFactory,CgliProxyFactoryb实现类。这两种实现类就对应着Mybatis的延迟加载的Javassist和Cgli实现

缓存问题 一级缓存 二级缓存

一级缓存:
    一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
    
    关闭或者使一级缓存失效的方法:
    1.局部配置 在某mapper.xml文件的select标签中直接增加设置flushCache="true"属性
    2.全局配置 在application.properties全局设置mybatis.configuration.local-cache-scope=statement
一级缓存的不足:
    使用一级缓存的时候,因为缓存不能跨会话共享,不同的会话之间对于相同的数据可能有不一样的缓存。在有多个会话或者分布式环境下,会存在脏数据的问题。如果要解决这个问题,就要用到二级缓存。


二级缓存:
  二级缓存是用来解决一级缓存不能跨会话共享的问题的,作为一个作用范围更广的缓存,它肯定是在SqlSession的外层,否则不可能被多个SqlSession共享。而一级缓存是在SqlSession内部的。二级缓存范围是 namespace 级别的 我也理解为SqlSessionFactory 层面的,可以被多个SqlSession共享    MyBatis查询数据的顺序是:二级缓存 —> 一级缓存 —> 数据库。
    1.使用示例
    <cache type="org.apache.ibatis.cache.impl.PerpetualCache"
               size="1024"
               eviction="LRU"
               flushInterval="15000"
               readOnly="false"/>
    2.关于多个xml用一个缓存的问题 可以使用cache-ref标签 假设A B两个Mapper共同用一个缓存 且缓存定义在AMapper.xml中  可以在BMapper.xml中增加 <cache-ref namespace="com.ccbckj.mapper.AMapper"/> 这个namespace对应AMapper.xml中的namespace


测试一级缓存(默认就是开启的)

    @RestController
    public class TestController {

        @Resource
        private SqlSessionFactory sqlSessionFactory;

        // 测试一级缓存默认开启
        @RequestMapping("test2")
        public String test2() {
            SqlSession session1 = sqlSessionFactory.openSession();
            TestMapper mapper1 = session1.getMapper(TestMapper.class);
            System.out.println("---->" + mapper1.test1(new HashMap<>()));
            System.out.println("---->" + mapper1.test1(new HashMap<>()));
            return "OK";
        }

    }


测试二级缓存(默认是关闭的)

    第一步:在application.properties全局配置 mybatis.configuration.cache-enabled=true 就开启整个项目的二级缓存 不设置true确实cache标签也会生效但是设置成false确实是关闭二级缓存

    第二步:在Mapper.xml 中配置<cache/>标签:
        <cache type="org.apache.ibatis.cache.impl.PerpetualCache"
            size="1024"
        eviction="LRU"
        flushInterval="120000"
        readOnly="false"/>

        flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

        其中eviction代表缓存回收策略,目前mybatis提供以下回收策略:
            LRU(Least Recently Used):最近最少使用的,回收最长时间不用的对象;
            FIFO(First in first out):先进先出,按照对象进入缓存的顺序来移除;
            SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象;
            WEAK:弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。

    @RestController
    public class TestController {
        @Resource
        private SqlSessionFactory sqlSessionFactory;

        // 测试 二级缓存
        @RequestMapping("test2")
        public String test2() {
            SqlSession session1 = sqlSessionFactory.openSession();
            TestMapper mapper1 = session1.getMapper(TestMapper.class);
            System.out.println("---->" + mapper1.test1(new HashMap<>()));
            System.out.println("---->" + mapper1.test1(new HashMap<>()));
            session1.commit();
            session1.close();


            SqlSession session2 = sqlSessionFactory.openSession();
            TestMapper2 mapper2 = session2.getMapper(TestMapper2.class);
            System.out.println("111---->" + mapper2.test2(new HashMap<>()));
            session2.commit();
            session2.close();
            return "OK";
        }
    }       

相关文章

网友评论

      本文标题:Mybatis 知识

      本文链接:https://www.haomeiwen.com/subject/gbuzprtx.html