Mybatis基础

基础

(1)一个持久层框架

(2)核心是输入映射和输出映射

    1.输入映射:向PreparedStatement中输入参数

    2.输出映射:将查询结果集自动映射为java对象

(3)架构:

    1.sqlMapConfig:mybatis全局配置文件,配置数据源、事物等mybatis运行环境,配置映射文件、mapper.xml........

    2.sqlSessionFactory:创建sqlSession回话

    3.sqlSession :操作数据库

    4.Executor执行器:sqlSession通过Executor来操作数据库

    5.mapped statement(底层封装对象):对数据库存储进行封装,包括sql语句,输入参数,输出结果类型

 

配置

springboot中的配置 其实如果基本使用甚至一跳都不用配置 又一次体现了springboot的强大

一般经常使用:

1.mybatis.configuration.mapUnderscoreToCamelCase=true  可以自动将数据库中的下划线转换成驼峰式命名

2.logging.level.com.spring.jiminshiro.mapper=debug 可以在控制台打印出生成的sql语句

configuration所有配置如下:

设置参数

描述

有效值

默认值

cacheEnabled

这个配置使全局的映射器启用或禁用缓存。

true | false

true

lazyLoadingEnabled

全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。

true | false

true

aggressiveLazyLoading

当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。

true | false

true

multipleResultSetsEnabled

允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动)。

true | false

true

useColumnLabel

使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两种方法来决定所使用的驱动。

true | false

true

useGeneratedKeys

允许JDBC支持生成的键。需要适合的驱动。如果设置为true则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如Derby)。

true | false

false

autoMappingBehavior

指定MyBatis如何自动映射列到字段/属性。PARTIAL只会自动映射简单,没有嵌套的结果。FULL会自动映射任意复杂的结果(嵌套的或其他情况)。

NONE,

PARTIAL,

FULL

PARTIAL

 

动态查询

mybatis相较于现在流行的其他ORM框架最主要的一点就是完全自己编写sql语句 可以在某些方面可能会有些复杂 但也大大增加了其灵活性

mybatis支持一下几种动态判断

if

choose (when, otherwise)

trim (where, set)

foreach

实例:

@Select("<script>" +
"select"+TAB_PARMER+
"from"+TAB+
"where " +
"id != 'null'" +
"<if test='employee.staffId != null'>and staff_id=#{employee.staffId}</if>" +
"<if test='employee.name != null'>and name=#{employee.name} </if>" +
"<if test='employee.mobile != null'>and mobile=#{employee.mobile} </if>" +
"<if test='employee.area != null'>and area=#{employee.area} </if>" +
"<if test='employee.gender != null'>and gender=#{employee.gender} </if>" +
"<if test='employee.isValid != null'>and is_valid=#{employee.isValid}</if>" +
"</script>") 

<WHERE> 与 WHERE 的区别 where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

<SET> 若语句的结尾为逗号,set 元素会将它们去除。

缓存

Mybatis中自带了缓存机制 将数据缓存设计成两级结构,分为一级缓存、二级缓存:

一级缓存

一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存 . 一个SqlSession对象会使用一个Executor对象来完成会话操作,Executor对象会维护一个Cache缓存,以提高查询性能。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改)

在查询后自动进行缓存 如果之后完全相同的查询会直接去缓存中查询 命中缓存会大大增加查询速度.但当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空,防止脏数据.

一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。

如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,通过localCacheScope指定。

<setting name="localCacheScope" value="STATEMENT"/>

一般建议初级玩家不要修改.

需要注意的是 当Mybatis整合Spring后,直接通过Spring注入Mapper的形式,如果不是在同一个事务中每个Mapper的每次查询操作都对应一个全新的SqlSession实例,这个时候就不会有一级缓存的命中,但是在同一个事务中时共用的是同一个SqlSession。

 

二级缓存

二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

一级缓存中,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。
当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

二级缓存配置

要正确的使用二级缓存,需完成如下配置的。

  1. 在MyBatis的配置文件中开启二级缓存。
    <setting name="cacheEnabled" value="true"/>
    
  2. 在MyBatis的映射XML中配置cache或者 cache-ref 。

cache标签用于声明这个namespace使用二级缓存,并且可以自定义配置。

<cache/>
  • type:cache使用的类型,默认是PerpetualCache,这在一级缓存中提到过。
  • eviction: 定义回收的策略,常见的有FIFO,LRU。
  • flushInterval: 配置一定时间自动刷新缓存,单位是毫秒。
  • size: 最多缓存对象的个数。
  • readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化。
  • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。

<cache-ref namespace="mapper.StudentMapper"/>

 

P.s. 对于缓存推荐阅读 美团技术团队的博客

 

Sql注入方式

注解方式

    String TABLE_LEAVE = "id,staff_id,start_date,end_date,day_num,type,area";
    String TABLE_LEAVE_PARAM = "#{id},#{staffId},#{startDate},#{endDate},#{dayNum},#{type},#{area}";
    String TABLE_EMPLOYEE = "id,staff_id,name,mobile,area,gender,is_valid";
    
    /**
     * 通过员工号查询 Employee been
     *
     * @param staffId 员工号
     * @return Employee been
     */
    @Select({"SELECT ", TABLE_EMPLOYEE, " FROM employee WHERE staff_id = #{staff_id}"})
    Employee findByEmployeeStaffId(@Param("staff_id") Long staffId);

    /**
     * 插入请假记录
     * @param leaveHoliday leaveHoliday been
     * @return 1:T 0:F
     */
    @Insert({"INSERT INTO leave_holiday( ", TABLE_LEAVE, " ) VALUES( ", TABLE_LEAVE_PARAM, " )"})
    Integer addLEAVE(LeaveHoliday leaveHoliday);

可以很方便的插入简单的sql语句, 加在方法上易于在代码编写过程中的使用. 可以用{ ... }的形式在其中使用 逗号 的形式拼接字符串 而不用使用加号的方式,并且也支持动态sql语句


XML方式

<mapper namespace="com.qunar.counter.dao.ContentDao">

    <sql id="all_fields">
        title AS title,
        number AS number,
        ch_number AS chNumber,
        en_number AS enNumber,
        punc_number AS puncNumber,
        num_number AS numNumber,
        link AS link
    </sql>

    <insert id="insert" parameterType="ContentModel">
        INSERT
        INTO
        content
        (
        title,
        number,
        ch_number,
        link
        )
        VALUES (
        #{title},
        #{number},
        #{chNumber},
        #{link}
        )
    </insert>

    <select id="query" resultType="ContentModel">
        SELECT
        <include refid="all_fields"/>
        FROM
        content
        order by id DESC
        limit #{pageNum},#{listNum}
    </select>

    <select id="count" resultType="Integer">
        SELECT
        count(*)
        FROM
        content
    </select>
</mapper>

在XML中进行配置sql 很方便的使用动态拼接语句 便于后期的维护

 

Provider方式

public class EmployeeProvider {

    public String insertEmployee(final Employee employee) {
        return new SQL() {
            {
                INSERT_INTO("employee");
                if (employee.getStaffId() != null) {
                    VALUES("staff_id", "#{staffId}");
                }
                if (employee.getName() != null) {
                    VALUES("name", "#{name}");
                }
                if (employee.getMobile() != null) {
                    VALUES("mobile", "#{mobile}");
                }
                if (employee.getArea() != null) {
                    VALUES("area", "#{area}");
                }
                if (employee.getGender() != null) {
                    VALUES("gender", "#{gender}");
                }
                if (employee.getIsValid() != null) {
                    VALUES("is_valid", "#{isValid}");
                }
            }
        }.toString();
    }
}

构建Provider类及其方法 使用java拼接的方式来构建动态sql语句 支持断点Debug 个人认为在复杂sql的情况下适合使用

    /**
     * 插入员工信息
     * @param employee 员工信息
     * @return 1:T 0:F
     */
    @InsertProvider(type = EmployeeProvider.class, method = "insertEmployee")
    @Options(useGeneratedKeys = true)
    Integer addEmployee(Employee employee);

调用方法:加@InsertProvider注解就可以调用 (@Options注解是为了让自增的id自动返回补全 方便单元测试断言)

比较

那这三种方法哪种最好呢? 答案是适合的就是最好的 简单的增删改查直接使用注解就可以 如果项目后期维护较多可以考虑使用XML的方式

而动态sql方面Provider非常好用 

但哪种方式最快呢?

2018-08-08 20:46:26.823  INFO 4476 --- [main] c.q.mybatistest.mybatis.bean.BeanTest    : Provider run 4120ms 

2018-08-08 20:46:54.429  INFO 10732 --- [main] c.q.mybatistest.mybatis.bean.BeanTest    : annotation run 6286ms 

2018-08-08 20:47:39.526  INFO 10336 --- [main] c.q.mybatistest.mybatis.bean.BeanTest    : XML run 7549ms 

都查询100W条记录 对其进行测试 发现provider的方式最快比其他两种方式快三分之一左右,而注解比XML快一点. p.s.使用默认的一级缓存

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值