Mybatis_笔记(二)

目录

一、特殊SQL语句

1. 模糊查询

 2. 批量删除

3.动态设置表名

4. 添加功能获取自增的主键

二、自定义映射关系(resultMap) 

1. 多对一映射处理

   a> 级联方式处理映射关系

   b> 使用association处理关系映射

   c> 分布查询

 3. 一对多映射处理

   a> collection映射处理

   b> 分布查询

三、动态SQL语句

1.  if 标签

2. where 标签

3. trim 标签

4. choose..when..otherwise 组合标签

5. foreach 标签

6. sql 标签

四、Mybatis的缓存

1. 一级缓存

2. 二级缓存

3. 缓存查询得顺序

四、拓展


一、特殊SQL语句

1. 模糊查询

   模糊查询的特殊之处 -- 使用" #{} "占位符赋值使用时要注意,因为在解析sql时会在引号内再次动态拼接一次引号(因为#{}有自动拼接引号的作用);而使用 " ${} " 就不会。

<!--UserEntity getLike(@Param("address") String address);-->
    <select id="getLike" resultType="userEntity">
        <!--1. 直接使用的方式-->
       select * from test_user where address like '%${address}%'
        <!--2. 拼接:select * from test_user where address like concat('%',#{address},'%')-->
        <!--3. select * from test_user where address like '%#{address}%'  这样会出错 -->
    </select>

第三方式的报错信息:

 2. 批量删除

   批量删除使用 where 字段名 in(1,2,3...)时是不可以使用" #{} "动态赋值的 -- 因为这样会添加上引号

   delete from test_user where id in (${ids})

   如果想删除除了这几个参数以外的数据的话用 not in

   delete from test_user where id not in (${ids})

3.动态设置表名

   动态设置表明也不可以使用" #{} ",因为正确的查询语句 表名是不能用引号的

 例如: select * from test_user

<!--List<User> getAllUser(@Param("tableName") String tableName);--> 
<select id="getAllUser" resultType="userEntity"> 
     select * from ${tableName} 
</select>

4. 添加功能获取自增的主键

useGeneratedKeys :开启主键自增
keyProperty :实体类中唯一的属性
因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user 对象的某个属性中
<!--int insertUser(UserEntity user);--> 
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> 
    insert into test_user values(null,#{username},#{password},#{address}) 
</insert>

二、自定义映射关系(resultMap) 

     若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合驼峰命名规则,此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
  • 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
  • 可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰
   例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为
userName

   若实体类中属性名和字段名不一致,可以通过resultMap来进行自定义映射

<!--resultMap:设置自定义映射 属性:
    id:表示自定义映射的唯一标识
    type:查询的数据要映射的实体类的类型
    子标签:
      id:设置主键的映射关系
      result:设置普通字段的映射关系
      association:设置多对一的映射关系
      collection:设置一对多的映射关系
      属性: property:设置映射关系中实体类中的属性名
            column:设置映射关系中表中的字段名 -->
    <resultMap id="userMap" type="UserEntity">
        <id property="id" column="id"></id>
        <result property="name" column="user_name"></result>
        <result property="password" column="password"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
    </resultMap>
    <!--List<User> testLike(@Param("str") String str);-->
    <select id="testLike" resultMap="userMap">
      <!--select id,user_name,password,age,sex from t_user where username like '%${str}%'-->
      select id,user_name,password,age,sex from t_user where user_name like concat('%',#{str},'%')
   </select>

1. 多对一映射处理

  指的是多个emp对像都对应某一条dept对象的数据

添加在Emp实体类中: private Dept dept;

   a> 级联方式处理映射关系


    <resultMap id="empDeptMap" type="Emp">
        <id column="eid" property="eid"></id>
        <result column="ename" property="ename"></result>
        <result column="age" property="age"></result>
        <result column="sex" property="sex"></result>
        <!--这里property="dept.did" 第二个实体类直接用类名.属性名-->
        <result column="did" property="dept.did"></result>
        <result column="dname" property="dept.dname"></result>
    </resultMap>
    <!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
    <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
          select emp.*, dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
    </select>

   b> 使用association处理关系映射

<!--使用association处理多对一映射关系-->
    <resultMap id="empDeptMap" type="Emp">
        <id column="eid" property="eid"></id>
        <result column="ename" property="ename"></result>
        <result column="age" property="age"></result>
        <result column="sex" property="sex"></result>
        <!--property="dept" - 对应Emp类中的属性名  javaType="Dept" - 对应的而实体类名-->
        <association property="dept" javaType="Dept">
            <id column="did" property="did"></id>
            <result column="dname" property="dname"></result>
        </association>
    </resultMap>
    <!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
    <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
        select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
    </select>

   c> 分布查询

   将多表联查拆分成单表查询,一层一层的进行查询,通过多次查询筛选到自己想要的数据。

 3. 一对多映射处理

  指一条Dept对象数据对应多条Emp对象数据

在Dept实体类中: private List<Emp> emp;

   a> collection映射处理

<!--collection处理多对一映射-->
    <resultMap id="deptEmpMap" type="Dept">
        <id property="did" column="did"></id>
        <result property="dname" column="dname"></result>
        <!--ofType:设置collection标签所处理的集合属性中存储数据的类型 -->
        <collection property="emps" ofType="Emp">
            <id property="eid" column="eid"></id>
            <result property="ename" column="ename"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
        </collection>
    </resultMap>
    <!--Dept getDeptEmpByDid(@Param("did") int did);-->
    <select id="getDeptEmpByDid" resultMap="deptEmpMap">
       select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did = emp.did where dept.did = #{did}
    </select>

   b> 分布查询

  将多表联查拆分成单表查询,一层一层的进行查询,通过多次查询筛选到自己想要的数据。

  分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载,此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"

三、动态SQL语句

1.  if 标签

   根据标签的test属性对应的表达式决定标签中的内容是否需要拼接到SQL中

<!--List<UserEntity> getIf(UserEntity user);-->
    <select id="getIf" resultType="UserEntity">
        select * from test_user where 1=1
            <if test="id !='' and id !=null">and id =#{id}</if>
            <if test="name !='' and name !=null">and name =#{name}</if>
            <if test="password !='' and password !=null">and password =#{password}</if>
            <if test="address !='' and address !=null">and address =#{address}</if>
    </select>

2. where 标签

   当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或者or去掉
   当where标签中没有内容时,此标签不会生效 (注)and或or标签只能添加在内容之前

<!--List<UserEntity> getWhere(UserEntity user);-->
    <select id="getWhere" resultType="UserEntity">
        select * from test_user
        <where>
            <if test="id !='' and id !=null">id =#{id}</if>
            <if test="name !='' and name !=null">and name =#{name}</if>
            <if test="password !='' and password !=null">and password =#{password}</if>
            <if test="address !='' and address !=null">and address =#{address}</if>
        </where>
    </select>

3. trim 标签

   若标签有内容时:
   prefix\suffix:将trim标签中内容前面\后面添加指定内容
   suffixOverrides\prefixOverrides: 将trim标签中内容前面\后面移除指定内容
   若标签没有内容时,trim标签也不回生效

<!--List<UserEntity> getTrim(UserEntity user);-->
    <select id="getTrim" resultType="UserEntity">
        select * from test_user
        <trim prefix="where" suffixOverrides="and|or">
            <if test="id !='' and id !=null">id =#{id} or</if>
            <if test="name !='' and name !=null"> name =#{name} and</if>
            <if test="password !='' and password !=null"> password =#{password} or</if>
            <if test="address !='' and address !=null"> address=#{address}</if>
        </trim>
    </select>

4. choose..when..otherwise 组合标签

    相当于java中的if..else if..else,when标签至少有一个.otherwise标签最多有一个

!--List<UserEntity> getChoose(UserEntity user);-->
    <select id="getChoose" resultType="UserEntity">
        select * from test_user
        <where>
            <choose>
                <when test="name !='' and name !=null">name =#{name}</when>
                <when test="address !='' and address !=null">address =#{address}</when>
                <otherwise>password =#{password}</otherwise>
            </choose>
        </where>
    </select>

5. foreach 标签

   如果传递过来的参数是一个数据,一个集合是就像需要循环来进行操作
   collection="ids" 要循环的数组\集合名称
   item="id"  标识数据的名称
   separator=","  以什么为间隔符号
   open="("  从什么符号开始
   close=")" 从什么符号结束

<!--List<UserEntity> getForeach(Integer[] ids);-->
    <select id="getForeach" resultType="UserEntity">
        select * from test_user where id
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </select>

    <!--Integer insertForeach(@Param("user") List<UserEntity> list);-->
    <insert id="insertForeach" >
        insert into test_user values
        <foreach collection="users" item="user" separator=",">
            (null,#{user.name},#{user.password},#{user.address})
        </foreach>
    </insert>

6. sql 标签

    可以记录一段公共sql片段,在使用的地方通过include标签进行引入

<sql id="ser">
        id,name,password,address
    </sql>
    <select id="xxx" resultType="UserEntity">
        select
        <include refid="ser"></include>
        from test_user
    </select>

四、Mybatis的缓存

   mybatis的缓存机制分为一级缓存和二级缓存两种机制,除了自带的,还可以整合第三方缓存,第三方缓存也是二级缓存。

1. 一级缓存

    一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

使一级缓存失效的四种情况:
  • 不同的SqlSession对应不同的一级缓存
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作
  • 同一个SqlSession两次查询期间手动清空了缓存

2. 二级缓存

    二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。

二级缓存开启的条件:

  •   a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  •   b>在映射文件中设置标签<cache />
  •   c>二级缓存必须在SqlSession关闭或提交之后有效
  •   d>查询的数据所转换的实体类类型必须实现序列化的接口 
<!--开启二级缓存 在mybatis-config.xml核心配置文件中配置 -->
<settings>    
     <setting name="cacheEnabled" value="true"/>
</settings>
<!-- 在mapper配置文件中配置 -->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache">
        <property name="eviction" value="LRU" />
        <property name="flushInterval" value="6000000" />
        <property name="size" value="1024" />
        <property name="readOnly" value="false" />
    </cache>

    PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。

* 二级缓存在mapper配置文件中添加cache标签可以设置的属性:
*   a> eviction属性: 缓存回收策略
*      LRU-最近最少使用的:移除最长时间不被使用的对象 (默认选项)
*      FIFO-先进先出:按照对象进入缓存的顺序来移除他们
*      SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象
*      WEAK-弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
*   b> flushInterval属性: 刷新间隔:缓存多长时间刷新一次,单位毫秒
*      默认情况是不设置的,缓存仅仅调用sql语句时刷新(调用增删改的语句才会刷新缓存)
*   c> size属性: 引用数目,正整数
*      代表缓存最多可以储存多少个对象,太大容易导致内存溢出
*   d> readOnly属性: 只读 true\false (默认false)
*      true:只读缓存,会给所有调用者返回缓存对象的相同实例;因此这些对象不能被修改,这提供了很重要的性能优势
*      false:读写缓存,会返回缓存对象的拷贝(通过序列化),但是性能上慢一些,但是安全

3. 缓存查询得顺序

  • a> 先查二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  • b> 如果二级缓存没有命中,在查询一级缓存
  • c> 如果一级缓存也没有命中,会查询数据库
  • d> sqlSession关闭后,一级缓存中的数据会写入二级缓存中

四、拓展

   Mybatis中除了上述功能,整合第三方缓存机制、分页插件、逆向工程都可以通过导入依赖来配置使用,建议使用Mybatis-Plus,指在mybatis基础上只做增强不做改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值