Mybatis的学习总结

1.MyBatis简介

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

回顾
对jdbc的封装框架有哪些:
Hibernate,dbutils,jdbcTemplate[spring],mybatis

2.MyBatis的框架核心(重要)

2.1两个配置

  1. Mybatis全局配置文件SqlMapConfig.xml
    作用:配置数据源(与spring结合后就交给spring了),加载映射文件,给模型取别名
<!--取别名-->
    <typeAliases>
        <!--方式1:单个的取别名,不实用-->
        <!--<typeAlias type="com.gyf.model.User" alias="user"></typeAlias>-->
        <!--方式2:给包取别名,批量实用,默认别名为类名(首字母大小写都可以)-->
        <package name="com.gyf.model"></package>
        <package name="com.gyf.vo"></package>
    </typeAliases>
  1. Mybatis映射文件 mapper.xml
    作用:构造出SqlSessionFactory,即会话工厂

2.2两个对象

  1. SqlSessionFactory
    作用:开启会话
sqlSession = sqlSessionFactory.openSession();
  1. sqlSession
    作用: 操作数据库
//selectOne查询一条结果
User user = sqlSession.selectOne("findUserById",25);

3.映射文件内的普通标签

  1. #{}:占位符 (可以防止sql注入问题)
  2. ${}:拼接sql(常用于模糊查询拼接字符串,例如:拼接模型参数:LIKE ‘%${user.username}%’ 拼接简单类型参数:LIKE ‘%${value}%’ )
  3. parameterType:接口中传入参数的类型(如果参数是简单类型,则#{}内任意命名,如果是模型,名称必须是模型的属性字段名)
  4. resultType:接口方法的返回值类型(用于sql查询的结果表列名和model的属性名一样)
  5. resultMap:接口方法的返回值类型(用于sql查询的结果表列名和model的属性名不一样,使使用前提,需要自己配置resultMap映射关系,用于复杂的关联查询,模型里有模型、集合等)

4. 动态SQL标签(if、where、foreach、sql片段)

  1. if和where( 注意:用if进行判断是否为空时,1.要判断null,2.要判断空字符串‘’《集合和数组就要判断size>0》;)
    用法:
<select id="findUserListDSQL" parameterType="userQueryVo" resultType="user">
        select * from user
        <where>
           <if test="user != null">
            <if test="user.sex != null and user.sex != ''">
                sex = #{user.sex}
            </if>
            <if test="user.username != null and user.username != ''">
                and username like '%${user.username}%'
            </if>
        </if>
        </where>
    </select>
  1. sql片段(提高SQL的可重用性)
    用法:
<sql id="select_user_where">
        <if test="user != null">
            <if test="user.sex != null and user.sex != ''">
                sex = #{user.sex}
            </if>
            <if test="user.username != null and user.username != ''">
                and username like '%${user.username}%'
            </if>
        </if>
    </sql>
    <select id="findUserListDSQL" parameterType="userQueryVo" resultType="user">
        select * from user
        <where>
          <!--refid 是sql片段的id -->
           <include refid="select_user_where"></include>
        </where>
    </select>
  1. foreach
    用法1:参数是集合
<!--SELECT * from user where id IN(1,10,16)-->
    <select id="findUserByIds" parameterType="userQueryVo" resultType="user">
        select * from user
        <where>
            <if test="ids != null and ids.size > 0">
                <!--collection:集合,写集合属性
                  item:遍历接收变量
                  open:遍历开始
                  close:遍历结束
                  separator:拼接格式
                  类似于java里的增强for循环
                  for(Integer id : ids){
                  }
                -->
                <!--userQueryVo模型里面的集合属性ids -->
                <foreach collection="ids" item="id" open="id in (" close=")" separator=",">
                    ${id}
                </foreach>
            </if>
        </where>
    </select>

用法2:参数是数组

 <!-- 参数是数组
       如果参数是数组的话,parameterType可以写全名【java.util.List】,也可以写别名list
       遍历或者判断的时候,都用list变量
   -->
    <!--SELECT * from user where id IN(1,10,16)-->
    <select id="findUserByIds2" parameterType="list" resultType="user">
        select * from user
        <where>
            <if test="list != null and list.size > 0">
                <foreach collection="list" item="id" open="id in (" close=")" separator=",">
                    ${id}
                </foreach>
            </if>
        </where>
    </select>

5.映射文件内的关联查询用到的标签(在 resultMap里用)

  1. association

作用于模型里有模型,类型用javaType

  1. collection

作用于模型里有集合或者集合里有集合,类型用ofType

6. mybatis与hibernate的区别【面试题】

  1. Mybatis技术特点

好处:
1、 通过直接编写SQL语句,可以直接对SQL进行性能的优化;
2、 学习门槛低,学习成本低。只要有SQL基础,就可以学习mybatis,而且很容易上手;
3、 由于直接编写SQL语句,所以灵活多变,代码维护性更好。
缺点:
4、 不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
a) Mysql:limit
b) Oracle:rownum
5、 需要编写结果映射。
应用场景:需求多变的互联网项目,例如电商项目。

  1. Hibernate技术特点

好处:
1、 标准的orm框架,程序员不需要编写SQL语句。
2、 具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。
a) 以后,mysql数据迁移到oracle,只需要改方言配置
缺点:
3、 学习门槛高,需要对数据关系模型有良好的基础,而且在设置OR映射的时候,需要考虑好性能和对象模型的权衡。
4、 程序员不能自主的去进行SQL性能优化。
应用场景:需求明确、业务固定的项目,例如OA项目、ERP项目等。

7.关联查询类型(一对一、一对多、多对多)

  1. 一对一 resultType实现

复杂查询时,单表对应的po类已不能满足输出结果集的映射。所以要根据需求建立一个扩展类(继承原模型)来作为resultType的类型。

<!--1.一对一 定单的扩展类(接收返回值,用resultType)-->
     <select id="findOrdersById" parameterType="int" resultType="ordersExt">
         SELECT o.*,u.username,u.address
         FROM orders o,`user` u
         WHERE o.user_id = u.id AND o.id = #{id}
     </select>
  1. 一对一 resultMap实现(掌握association的使用)

根据sql查询出来的表字段名,涉及到多张表的字段,结合已有的模型(一表一模型),无法接收表的返回值,这时让模型里再装缺少的模型,给set、get方法。在resultMap,用association给模型里的模型配置映射。

<!--2.一对一 模型里有模型(接收返回值,用resultMap  )-->
    <resultMap id="orderResultMap" type="orders">
        <!--往orders的模型匹配数据-->
        <id property="id" column="id"></id>
        <result property="number" column="number"></result>
        <result property="createtime" column="createtime"></result>
        <result property="note" column="note"></result>
        <!--往orders的user匹配数据
        模型里模型,使用association来配置
        -->
        <association property="user" javaType="user">
            <id property="id" column="user_id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
        </association>
    </resultMap>
    <select id="findOrdersById2" parameterType="int" resultMap="orderResultMap">
         SELECT o.*,u.username,u.address
         FROM orders o,`user` u
         WHERE o.user_id = u.id AND o.id = #{id}
     </select>
  1. 一对多 resultMap实现(掌握collection的使用)

作用于模型里有集合属性,给这个属性配置映射关系

<resultMap id="orderResultMap3" type="orders">
        <!--往orders的模型匹配数据-->
        <id property="id" column="id"></id>
        <result property="number" column="number"></result>
        <result property="createtime" column="createtime"></result>
        <result property="note" column="note"></result>
        <!--往orders的user匹配数据
        模型里有模型,使用association来配置
        -->
        <association property="user" javaType="user">
            <id property="id" column="user_id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
        </association>
        <!--往orders的orderDetails匹配数据
        模型里有集合,使用collection来配置,模型类型用ofType
        -->
        <collection property="orderDetails" ofType="orderDetail">
            <id property="detailId" column="detail_id"></id>
            <result property="itemsId" column="items_id"></result>
            <result property="itemsNum" column="items_num"></result>
        </collection>
    </resultMap>
    <select id="findOrdersById3" parameterType="int" resultMap="orderResultMap3">
         SELECT o.*,u.username,u.address,od.id detail_id,od.items_id,od.items_num
         FROM orders o,user u,orderdetail od
         WHERE o.user_id = u.id
         AND o.id = od.orders_id
         AND o.id = #{id}
     </select>
  1. 多对多 resultMap实现(一对一和一对多的综合运用)

适用于模型1里有集合模型1,集合模型1里有集合模型2,集合模型2里有模型2等等,复杂的关联查询

<resultMap id="duoduiduo" type="user">
        <!--往user模型匹配数据-->
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>
        <!--往user的orders匹配数据,orders是集合,模型里有集合,用collection配置,类型用ofType-->
        <collection property="orders" ofType="orders">
            <id property="id" column="orders_id"/>
            <result property="number" column="number"/>
            <result property="createtime" column="createtime"/>
            <result property="note" column="note"/>
            <!--往orders的orderDetails匹配数据,orderDetails也是集合,集合里有集合,还是用collection配置,类型用ofType-->
            <collection property="orderDetails" ofType="orderDetail">
                <id property="detailId" column="detail_id"/>
                <result property="itemsId" column="items_id"/>
                <result property="itemsNum" column="items_num"/>
                <!--往orderDetails的item匹配数据,item是模型,用association,类型用javaType-->
                <association property="item" javaType="items">
                    <result property="name" column="name"/>
                    <result property="detail" column="detail"/>
                </association>
            </collection>
        </collection>
    </resultMap>
    <select id="findUserAndItemInfo" resultMap="duoduiduo">
         SELECT  u.id,u.username,u.address,
				 o.id orders_id,o.number,o.createtime,o.note,
				 od.id detail_id,od.items_id,od.items_num,it.name,it.detail
         FROM user u,orders o,orderdetail od,items it
         WHERE o.user_id = u.id
         AND o.id = od.orders_id
         AND od.items_id = it.id
    </select>

8.延时加载(懒加载)

先加载主信息,在需要的时候,再去加载从信息。节省资源。

 <!--============================懒加载(延迟加载),!!!起作用需要在全局配置文件里设置setting 设为true===============================-->
    <resultMap id="lazyLoading" type="orders">
        <id property="id" column="id"/>
        <result property="user_id" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createtime" column="createtime"/>
        <result property="note" column="note"/>
        <!--配置orders里的模型user属性使用懒加载,模型里有模型,使用association,!!!这种方式的前提是有public User findUserById(int id);这个方法-->
        <association property="user" select="com.gyf.mapper.UserMapper.findUserById" column="user_id"></association>
    </resultMap>
    <select id="findOrdersAndUserByLazyLoading" resultMap="lazyLoading">
        select * from orders
    </select>

sqlMapConfig.xml内配置

 <settings>
        <!--懒加载开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

9.查询缓存(一级、二级)

一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。
二级缓存指的就是同一个namespace下的mapper,即SqlSessionFactory
在这里插入图片描述

9.1一级缓存使用(默认开启)

  1. 解释

mybatis默认使用开启了以及缓存,一级缓存就是指sqlSession,通过它分别先后获取同一个user对象,默认只执行一次sql,第二次同样的查询,会从一级缓存里直接获取;如果在两次获取对象中间加入了更新操作(删除,修改,删除),则一级缓存会被清空,前面的user2,将会自己执行sql语句,查询,此过程有3次sql查询。

  1. 原理图
    在这里插入图片描述
  2. 代码演示
 /**
     * 一级缓存SqlSession
     * @throws IOException
     */
   @Test
    public void test1() throws IOException {
       //1.读取配置文件;
       String resouce = "SqlMapConfig.xml";
       InputStream is = Resources.getResourceAsStream(resouce);
       //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
       SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
       SqlSessionFactory ssf = sqlSessionFactoryBuilder.build(is);
       //3.获取sqlSession对象
       SqlSession sqlSession = ssf.openSession();
       UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
       User user1 = userMapper.findUserById(1);
       System.out.println("user1:"+user1);

       //保存操作,加入此操作,一级缓存将被清空,后面同样的查询需要再执行sql语句(若此处加入修改,删除操作,一级缓存也会被清空)
       userMapper.save(new User("广东雨神",null,null,"广东"));//不加入,则查询两次id=1,就只用执行一次sql

       User user2 = userMapper.findUserById(1);
       System.out.println("user2:"+user2);

       //提交并关闭sqlSession
       sqlSession.commit();
       sqlSession.close();
   }

9.2二级缓存使用(手动开启)

  1. 解释

二级缓存就是指SqlSessionFactory,清空情况跟以及缓存一样

  1. 使用前提条件
  • 1.在全局配置文件setting里加入二级缓存允许配置
    * 2.在指定的mapper.xml命名空间下配置缓存cache标签
    * 3.调用的模型需要实现序列化
    * 4.sqlSession关闭了才会写入二级缓存
  1. 原理图
    在这里插入图片描述
  2. 代码演示
 public void test2() throws IOException {
        //1.读取配置文件;
        String resouce = "SqlMapConfig.xml";
        InputStream is = Resources.getResourceAsStream(resouce);
        //2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory ssf = sqlSessionFactoryBuilder.build(is);
        //3.创建多个sqlSession
        SqlSession sqlSession1 = ssf.openSession();
        SqlSession sqlSession2 = ssf.openSession();
        SqlSession sqlSession3 = ssf.openSession();
        //4.创建多个mapper
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);

        //5.二级缓存作用验证
        //第一次查询
        User user1 =  mapper1.findUserById(1);
        System.out.println("user1:"+user1);
        sqlSession1.close();

        //保存操作或其他修改、删除,提交后,会清除二级缓存.类似于一级缓存
      /*  mapper3.save(new User("斗神",null,null,"广东"));
        sqlSession3.commit();
*/
       //第二次查询
        User user2 = mapper2.findUserById(1);
        System.out.println("user2:"+user2);
        sqlSession2.close();
    }

sqlMapConfig.xml内配置

 <settings>
        <!--二级缓存开关-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
  1. 应用场景
    对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存技术。(建议使用时设置一下刷新间隔(cache标签中有一个flashInterval属性)来定时刷新二级缓存)
  2. 单独禁用某方法使用缓存(了解)
    在这里插入图片描述
  3. 设置更新操作时,该方法不清空二级缓存(了解)
    在这里插入图片描述

9.3 二级缓存,使用第三方框架ehcache(推荐)

思路:

Cache是一个接口,它的默认实现是mybatis的PerpetualCache。如果想整合mybatis的二级缓存,那么实现Cache接口即可。

  1. ehcache与mybatis的缓存对比

Mybatis本身是一个持久层框架,它不是专门的缓存框架,所以它对缓存的实现不够好,不能支持分布式。Ehcache是一个分布式的缓存框架。

  1. 分布式

系统为了提高性能,通常会对系统采用分布式部署(集群部署方式)
在这里插入图片描述
3.使用前提
1.导包
* 2.在指定的mapper.xml命名空间下配置缓存cache标签,type里类的路径
* 3.添加ehcache.xml配置文件

mapper.xml配置
在这里插入图片描述
ehcache配置
在这里插入图片描述

10. SqlMapConfig.xml加载映射文件(推荐方式)

 <!--告诉mybatis加载映射文件-->
    <mappers>
        <!--加载映射文件的方式三 注册指定包下的所有映射文件(推荐,可以批量,简单高效,一劳永逸)-->
        <package name="com.gyf.mapper"></package>
    </mappers>

11.SqlMapConfig.xml内取别名(推荐方式)

 <typeAliases>
        <!--给包取别名,批量实用,默认别名为类名(首字母大小写都可以)-->
        <package name="com.gyf.model"></package>
        <package name="com.gyf.vo"></package>
    </typeAliases>

12.Spring与Mybatis整合(推荐使用mapper扫描方式)

整合详情见项目ssm

12.1ApplicationContext.xml内批量创建mapper的bean对象(推荐使用)

<!-- 批量创建mapper的bean对象,内部会扫描指定包下的mapper,创建代理对象,名字就是类名,头字母改小写
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- mapper代理开发方式之批量mapper配置  ,bean的名字默认为mapper接口类名的首字母小写
			注意:
			1.jdk1.8 用这种方式,bean不能创建成功 ,改成jdk1.7的即可
			2.或者spring我换成spring3.2.9或以上就OK了
        -->
        <property name="basePackage" value="com.gyf.backoffice.mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
    </bean>

13.逆向工程

可以生成指定表的模型,mapper接口以及mapper.xml,默认有简单的CRUD(增删改查)功能。开发中常用,极大地提高了开发效率。
项目见:AutoGenerator

14.补充:主键返回之MySQL自增主键

思路:

 MySQL自增主键,是指在insert之前MySQL会自动生成一个自增的主键。
 我们可以通过MySQL的函数获取到刚插入的自增主键:
LAST_INSERT_ID()
 这个函数是在insert语句之后去调用。

mapper.xml

<insert id="insertUser" parameterType="com.gyf.domain.User">
		<!-- 
			[selectKey标签]:通过select查询来生成主键
			[keyProperty]:指定存放生成主键的属性
			[resultType]:生成主键所对应的Java类型
			[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句
			[last_insert_id]:MySQL的函数,要配合insert语句一起使用 -->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		<!-- 如果主键的值是通过MySQL自增机制生成的,那么我们此处不需要再显示的给ID赋值 -->
		INSERT INTO USER (username,sex,birthday,address) 
		VALUES(#{username},#{sex},#{birthday},#{address})
</insert>

总结

花了两天时间学习mybatis持久层框架,首先对框架的全局配置文件sqlMapConfig.xml有了了解,里面用来配置数据源以及加载映射mapper的方式。接着搭建了mybatis的项目,由model,mapper,test组成,mapper取代了以前的dao的方式,这种方式不用写dao的实现类,换成mapper.xml。接着对mapper.xml里标签属性进行了联系,包括if,where,foreach等,即动态SQL,另外做了一个关联查询的操作,涉及一对一,一对多,多对多;模型里有模型,模型里有集合,集合里有集合,集合里模型等复杂的关联查询。这个是根据业务需求得到的结果表而定的。掌握了association、collection的使用,然后就是掌握三种推荐配置文件的使用方式,会提高效率;除此之外,还学习了mybatis的一级缓存和二级缓存(推荐使用支持分布式的第三方缓存框架ehcache)最后,会用mybatis的逆向工程。学习框架的意义在于简化代码,提高开发效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值