MyBatis随笔

Mybatis概览


  • 此文章仅个人笔记,非知识点博客文章
  • 对原生态JDBC程序的封装
  • mybatis开发DAO的方法(两种):
    • 原始DAO方法(程序需要编写DAO接口与实现类)
    • mybatis的mapper接口(相当于DAO接口)代理开发
  • mybatsi的核心:
    • mybatis输入映射
    • mybatis输出映射
  • mybatis的动态SQL
  • mybatis延迟加载
  • mybatis高级结果集映射
  • 包含一个全局的配置文件与映射关系文件,如:mybatis.xml(全局配置文件), mapper.xml(映射文件)

Mybatis框架


  • mybatis为apache下的一个持久层框架,mybatis开发更多的是专注于SQL,开发自由灵活
  • mybatsi可以向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成Java对象(输出映射)
  • 通过SqlSessionFactory创建SqlSession, 通过sqlSession的Executor(分两种:基本的与缓存的)去操作(CRUD)数据库

Mybatis入门


  • 开发环境:

    • mybatis的jar包
    • log4j.properties(用于查看日志),可从mabatis的配置文件中找到,开发环境设置为debug级别,上线环境设置为info级别,如:

      log4j.rootLogger=DEBUG, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
      
  • 全局配置文件mybatis.xml:

    <configuration>
        <!-- 与Spring整合后environment配置将移除 -->
        <environments>
            <environment id="development">
                <!-- 使用jdbc事物管理,事物控制由mybatis -->
                <transactionManager type="JDBC" />
                <!-- 数据库连接池, 由mybatis管理 -->
                <dataSource type="POOLED">
                    <prioperty name="driver" value="..." />
                    <prioperty name="url" value="..." />
                    <prioperty name="username" value="..." />
                    <prioperty name="password" value="..." />
                    <!-- ... -->
                </dataSource>
            </environment>
        </environments>
    
        <!-- 配置映射文件 -->
        <mappers>
            <mapper resource="sqlMapper/User.xml" />
        </mappers>
    </configuration>
    
  • 映射文件User.xml:

    <mapper namesapce="user">
        <!-- 在映射文件中可以配置多个SQL语句对应不同的数据库操作 -->
        <!-- 
            finUserById: 为statement的id
            parameterType:指定输入参数的类型
            resultType:指定输出的结果集映射的Java对象类型
            #{id}: 其中的id表示接收输入的参数,参数名称就是id,如果输入参数是简单类型,#{}中的参数可以任意,可以其他任何名称
            模糊查询使用$符(不建议使用),注意易引起SQL注入,切传入的名称只能是value,如下
        -->
        <select id="findUserById" parameterType="int" resultType="com.demo.User">
            select * from user where id=#{id}
        </select>
        <select id="findUserByName" parameterType="int" resultType="com.demo.User">
            select * from user where username like '%${value}%'
        </select>
    </mapper>
    
  • mysql获取插入的自增id值,使用last_insert_id()方法,如:

    select last_inser_id()
    
    • 映射的SQL如下:

      <insert id="inserUser" parameterType="com.demo.User">
          <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
              select last_insert_id()
          </selectKey>
          insert into user value(#{username}, #{birthday}, #{sex}, #{address})
      </user>
      
  • Mybatis与Hibernate的本质区别与应用场景:
    • Hibernate:标准ORM框架,sql语句自动生成,对SQL语句进行优化困难,适用于需求变化不多的中小型项目,如后台管理系统:erp,、orm、oa
    • Mybatis:专注于SQL本身,需要编写SQL,sql的修改优化方便,不完全的ORM框架,适用于需求变化较多的项目,如互联网项目

Mybatis开发DAO的方法

  • SqlSessionFactoryBuild创建SqlSessionFactory
  • SqlSessionFactory创建SqlSession,SqlSessionFactory可以单例创建
  • SqlSession是非线程安全的,SqlSession的最佳应用场合是在方法体内,即定义为局部变量
  • DAO开发:
    • 原始方法DAO开发:
      • 编写DAO接口
      • 编写DAO接口实现类
    • mapper代理方法开发DAO:
      • 只需要编写DAO接口,即mapper接口
      • 编写对应的mapper.xml映射文件
      • Mybatis可以自动生成mapper接口实现类的代理对象
      • mapper接口开发规范:
        • 在mapper.xml中namespace属性值等于mapper接口地址,如:com.demo.mapper.UserMapper
        • mapper.xml中的statement的id需要与mapper接口类的方法名相同
        • mapper.xml中的statement的parameterType指定的类型需要与mapper接口类中的方法输入参数类型一致
        • mapper.xml中的statement的resultType指定的类型需要与mapper接口类中的方法返回值类型一致
      • 通过使用SqlSession的getMapper方法获取mapper接口代理对象
  • Mybatis全局配置文件mybatis.xml:

    • properties(属性):如数据库的链接信息
    • settings(全局配置参数):如开启二级缓存、延迟加载等
    • typeAliases(类型别名):可以用于定义POJO的别名,如:

      <!-- 单个别名定义 -->
      <typeAlias alias="user" type="com.demo.User" />
      <!-- 批量定义别名,别名就是类名首字母小写 -->
      <package name="com.demo" />
      
    • typeHandlers(类型处理器):完成JDBC与Java类型的转换
    • objectFactory(对象工厂):
    • mappers(映射器):加载映射文件,通过resource属性加载单个映射文件

      • 使用相对于类路径的资源:

        <mapper resource="sqlMap/User.xml" />
        
      • 使用完全限定路径:

        <mapper url="file:///D:workspace_20170712\mybatis\sqlMap\User.xml" />
        
      • 使用mapper接口类路径(要求mapper接口名称与mapper映射文件名称一致且在同一目录下):

        <mapper class="com.demo.mapper.UserMapper" />
        
      • 批量加载资源(要求与使用mapper接口类路径一致):

        <package name="com.demo" />
        
  • 输出映射(resultType):
    • 只有查询的列名或别名与POJO的属性名一致时才能创建成功
  • 使用resultMap完成高级映射:

    • 如果查询出来的列名与POJO的属性名不一致,通过定义一个resultMap对列名和POJO属性名之间做一个映射关系
    • 定义resultMap,使用resultMap作为statement的输出映射类型

      <!-- type:resultMap最终映射的Java对象类型,可以使用别名
          id:对resultMap的唯一标识
       -->
      <resultMap type="com.demo.User" id="userResultMap">
          <!-- id表示查询结果集中唯一标识,
              column:查询出来的列名
              property:type指定的POJO的属性名
              result表示查询结果集中普通标识
          -->
          <id column="" property="" />
          <result column="" property="" />
      </resultMap>
      

动态SQL

  • 在sql中使用where, if标签,如:

    <select id="findUserCount" parameterType="com.demo.User" resultType="int">
        select count(*) from user
        <where>
            <if test="username!=null">
                and user.username="${username}"                
            </if>
            //...               
        </where>
    </select>
    
  • Sql片段(提高重用性):

    • 不要在sql片段中使用where标签
    • 在SQL中使用where的子标签include来引用sql片段
    • 如:

      <sql id="query_user_where">
          <if test="username!=null">
              and user.username="${username}"                
          </if>
          //...   
      </sql>      
      
      <select id="findUserCount" parameterType="com.demo.User" resultType="int">
          select count(*) from user
          <where>
              <include refid="query_user_where" />
          </where>
      </select>
      

高级映射

  • 将关联查询的列映射到一个POJO属性中(一对一)
  • 将关联查询的列映射到一个List中(一对多)
  • 关联查询的resultMap:

    • 查询到单一记录时,使用association标签,如:

      • JavaBean:

        public class Order{
            private int id;
            private String orderName;
            private User user;
            private List<OrderDetail> orderDetails;
            //....
        }
        
        public class User{
            private int id;
            private String userName;
            private String sex;
            //...
        }
        
      • resultMap:

        <resultMap type="com.demo.Order" id="orderWithUser">
            <id column="order_id" property="id" />
            <result column="order_name" property="orderName" />
        
            <!-- 关联查询的user -->
            <association property="user"  javaType="com.demo.User" >
                <id column="user_id" property="id"/>
                <result column="user_name" property="userName"/>
            </association>
        </resultMap>
        
    • 查询到多条记录时使用collection标签,如:

      <resultMap type="com.demo.Order" id="orderWithUser" extends="orderWithUser">
          <!-- 使用了extends,所示可以省略当前的order属性映射 -->
          <id column="order_id" property="id" />
          <result column="order_name" property="orderName" />
          <collection property="orderDetails" ofType="com.demo.OrderDetail">
              <id column="" property="" />
              <result column="" property="" />
          </collection>
      </resultMap>
      
  • resultType与resultMap的比较:
    • resultType使用更加方便
    • resultMap可以实现延迟加载,而resultType则不行

延迟加载

  • association与collection具有延迟加载的功能
  • association使用select属性指定延迟加载的statement的id,使用column属性指定关联查询的列名
  • mybatis需要开启延迟加载,默认是未开启,如下方式在全局配置文件中开启懒加载:

    <settings>
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="aggressiveLazyLoading" value="false" />
    <settings>
    

查询缓存

  • 一级缓存 - SqlSession级别的缓存
    • 在SqlSeesion对象中有一个数据结构(HashMap)用于存储缓存数据,不同的SqlSession之间的缓存区域互不影响
    • SqlSession执行commit操作(insert、update、delete)后,会清空SqlSession中的一级缓存
    • mybatis默认支持一级缓存
  • 二级缓存 - Mapper级别的缓存

    • 多个SqlSession去操作同一个Mapper的SQL语句,二级缓存是跨SqlSession的
    • mybatis的二级缓存需要手动开启
    • 二级缓存的缓存区域是按照namespace区分的,即每一个namespace的mapper都存在一个二级缓存区域
    • 二级缓存的开启需要在全局配置文件中配置,同时也需要在需要开启的mapper的配置文件中设置

      • 在全局文件的配置如下:

        <setting name="cacheEnabled" value="true" />
        
      • 在Mapper配置文件中的配置如下:

        <!-- 其中的type属性可以设置自定义的Cache实现类或第三方框架的Cache实现类 -->
        <cache />   
        
    • 对应的POJO类应该实现序列化接口,以便将缓存数据取出并实现反序列化操作,因为二级缓存的数据存储介质不一定在内存中
    • SqlSession执行close操作之后才能将数据保存到二级缓存
    • 使用useCache属性可以禁用二级缓存,使用flushCache可以刷新(清空)二级缓存,默认值均为true,如:

      <select id="findUserById" resultType="com.demo.User" useCache="false">
          //sql...
      </select>
      
  • ehcache、redis、memcached是一个分布式的缓存框架
  • mybatis提供了一个cache接口,实现自定义的缓存机制,Mybatis默认实现的Cache类为PrepetualCache,开发自定义的缓存逻辑时可以参考默认的Cache类实现
  • 使用ehcache框架时,需要配置相应的ehcache文件:

  • 一级缓存是针对一个SqlSession,而二级缓存是针对多个SqlSession的

Mybatis整合Spring

  • Mybatis与Spring整合 - sqlSessionFactory配置

    • 持久层的mapper都需要spring管理,需要spring通过单例方式管理sqlSessionFactory
    • 整合环境(jar包):
      • mybatis
      • spring
      • mybatis与spring的整合包(mybatis-spring.jar)
    • 在spring的配置文件(applicationContext.xml)中配置sqlSessionFactory

      <!-- 加载配置文件 -->
      <context:property-placeholder location="classpath:db.property" />
      <!-- 数据库连接池 -->
      <bean id="dataSource" class="">
          <property name="" value="" />
          <!-- 数据源的信息 -->
      </bean>
      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
          <property name="configLocation" value="mybatis.xml" />
          <!-- dataSource -->
          <property name="dataSource" ref="dataSource" />
      </bean>
      
  • mybatis与spring整合后的原始DAO开发:

    • 创建mapper.xml映射文件与DAO接口及其实现类
    • 在全局文件中通过mappers元素加载映射文件
    • 在创建DAO实现类时,使其继承SqlSessionDaoSupport类,使得不用在实现类类中显示的声明SqlSessionFactory属性,在DAO方法中使用this.getSqlSession()获取SqlSession,如下:

      public class UserDAOImpl extends SqlSessionDaoSupport implements UserDAO{
          public User findUserById(int id){
              SqlSession sqlSession = this.getSqlSession();
              //操作数据库,方法结束自动关闭sqlSession,不需要显示close
              return user;
          }
      }
      
      在spring配置文件中配置DAO:
      <bean id="userDAO" class="com.demo.mm.dao.UserDAOImpl">
              <property name="sqlSessionFactory" ref="sqlSessionFactory" />
      </bean>
      
  • mybatis与spring整合后的mapper代理开发:

    • 创建Mapper接口类及其mapper.xml文件
    • 在spring的配置文件中配置mapper,通过MapperFactoryBean创建代理对象:

      <!-- MapperFactoryBean根据mapper接口生成代理对象 -->
      <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
          <!-- 指定mapper接口, mapperInterface为MapperFactoryBean的属性名 -->
          <property name="mapperInterface" value="com.demo.mm.mapper.UserMapper" />
          <property name="sqlSessionFactory" ref="sqlSessionFactory" />
      </bean>
      
    • mapper的批量配置,从mapper包中扫描mapper接口,自动创建代理对象并且在spring容器中注册(建议使用):

      <!-- 在spring中加入mapper扫描后,在mybatis的配置文件中就不需要再加入扫描mapper -->
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
          <!-- 
              1.指定扫描的包名,basePackage为MapperScannerConfigurer类中的属性名 
              2.mapper.java与mapper.xml的文件名需要保持一致,且在同一目录中
              3.如果扫描多个包不能使用通配符,只能使用逗号分隔
          -->
          <property name="basePackage" value="com.demo.mm.mapper" />
          <!-- 此处不能使用sqlSessionFactory -->
          <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
      </bean> 
      

逆向工程

  • mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码,如下:
    • mapper.java
    • mapper.xml
    • POJO类
  • 在实际开发中,常用的逆向工程方式为由数据库的表生成java代码
  • 下载mybatis逆向工程:
    • mybatis-generator-core-(version)-bundle
  • 逆向工程的使用:
    • 使用Java程序与XML配置文件的方式
  • 具体配置参考官方文档

猜你喜欢

转载自blog.csdn.net/djh_happy/article/details/76407277