小浊微清的博客

MyBatis初解

2017-06-09  本文已影响42人  小浊微清

MyBatis是一种半自动映射的框架。是目前较为流行的Java ORM框架。(ORM模型是指数据库的表与Java的POJO的映射关系模型,解决之间的相互映射。)本文主要是我在学习了《深入浅出MyBatis技术原理与实战》后的自我总结。

配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 全局映射器启用缓存 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 全局延时加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 不对带有延时加载属性的对象完全加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 对单一SQL允许返回多结果集 -->
        <setting name="multipleResultSetsEnabled" value="true"/>
        <!-- 允许使用列标签代替列名 -->
        <setting name="useColumnLabel" value="true"/>
        <!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
        <setting name="useGeneratedKeys" value="true"/>
        <!-- 自动映射任意复杂的结果集 -->
        <setting name="autoMappingBehavior" value="FULL"/>
        <!-- 简单执行器  -->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!-- 数据库超过25000秒仍未响应则超时 -->
        <setting name="defaultStatementTimeout" value="25000"/>
        <!-- 配置使用log4j记录日志-->
        <setting name="logImpl" value="log4j"/>
        <!-- 自动转换驼峰命名 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

这是简单Mybatis的设置。依然还有许多属性我们没有提到。在我们的设置中,autoMappingBehavior是有三种设置:NONE(取消自动映射)、PARTIAL(只会映射没有定义嵌套结果集映射的结果集,在缺省配置的情况下默认)、FULL;而defaultExecutorType表示执行器executor类型,分为三种:SIMPLE(普通执行器,默认情况下是SIMPLE)、REUSE(执行器会重用预处理语句prepared statements)、BATCH(执行器会重用语句并执行批量更新)。

在configuration中还会涉及其他属性,常用的有typeAliases(类型命名)、typeHandler(类型处理器)、plugins(插件)等。而对于typeHandler的配置里,又有javaType与jdbcType,typeHandler就是解决其转换的问题。

MyBatis-Spring

一般情况下,我们大多数情况下是在Spring中使用MyBatis,即需要配置MyBatis-Spring。分为五步进行配置:

先配置数据源。

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="#{jdbc['jdbc.url']}"/>
        <property name="username" value="#{jdbc['jdbc.username']}"/>
        <property name="password" value="#{jdbc['jdbc.password']}"/>
        <!-- 配置初始化大小、最小、最大 -->
        <property name="minIdle" value="#{jdbc['ds.minIdle']}"/>
        <property name="maxActive" value="#{jdbc['ds.maxActive']}"/>
        <property name="initialSize" value="#{jdbc['ds.initialSize']}"/>
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="#{jdbc['ds.maxWait']}"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="#{jdbc['ds.timeBetweenEvictionRunsMillis']}"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="#{jdbc['ds.minEvictableIdleTimeMillis']}"/>
        <property name="validationQuery" value="SELECT 1"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
        <property name="poolPreparedStatements" value="false"/>
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat"/>
    </bean>

这儿我们使用的Druid数据源。接下来配置SqlSessionFactory。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 主配置文件 -->
        <property name="configLocation" value="classpath:/mybatis-config.xml"/>
        <!-- 自动扫描sqlmap目录下的所有SQL映射的xml文件 -->
        <property name="mapperLocations" value="classpath:mappers/*.xml"/>
        <!-- 自动注册javabean别名 默认会使用javabean的首字母小写的非限定类名来作为它的别名-->
        <property name="typeAliasesPackage" value="fei.self.model"/>
    </bean>

<!-- spring与mybatis整合配置,扫描所有dao -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 扫描基本包路径下的所有映射器接口类 采用分号或者逗号分隔 可设置多个包路径 -->
        <property name="basePackage" value="com.ximalaya.ops.fei.self.dao"/>
        <!--多个数据源 可设置具体的sqlSessionFactoryBean 单个数据源不必配置-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

这儿的mybatis-config.xml就是我们之前的configuration以及setting的那个文件。并且在这儿,我们配置了自动扫描信息,包括扫描所有的DAO以及Mapper文件。接下来只剩下事务处理的配置了。

<!-- 对dataSource 数据源进行事务管理 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>

    <!-- 事务管理 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 对insert,update,delete 开头的方法进行事务管理,只要有异常就回滚 -->
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="reset*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <tx:method name="getExecution*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
            <!-- select,count开头的方法,开启只读,提高数据库访问性能 -->
            <tx:method name="select*" read-only="true"/>
            <tx:method name="count*" read-only="true"/>
            <!-- 对其他方法 使用默认的事务管理 -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

<!-- 启用对事务注解的支持 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

这是最基础的MyBatis-Spring的配置。这部分其实挺无趣的,个人觉得MyBatis最有趣的就是接下来的MyBatis的技术原理以及插件等。关于Mapper的一些在这儿不作罗列了。

动态SQL

所谓动态SQL,指的是一些特殊的MyBatis标签的使用,从而对于SQL的拼装具有动态性的效果。主要是if、choose、trim、foreach以及bind元素这些。这部分其实挺有趣的,可以增加我们对于MyBatis的掌握。这部分的知识在这儿不作罗列,看一些例子都能明白。

MyBatis原理

终于到了重点且有趣的地方,这部分知识可以帮助我们理解MyBatis,然后能写一些好用的插件。

在学习之前需要掌握动态代理,分为JDK动态代理与CGLIB动态代理。

首先,需要构建SqlSessionFactory。第一步,先通过XMLConfigBuilder解析配置文件,存入Configuration类中(这个类里基本保存了所有的配置)。第二步,使用Configuration去构建SqlSessionFactory。对于SqlSessionFactory,这是一个接口,在一般MyBatis中用DefaultSqlSessionFactory的实现类,对于接口的方法都做了实现。

第二个需要掌握的是Mapper映射器。我们提到过,在Configuration中,有所有的配置,当然映射器也在里面。需要了解的是,Mapper映射是通过动态代理的方式实现的。一般映射器里面包含有三部分:MappedStatement:用户保存映射节点;SqlSource:这是MappedStatement的一个属性,一个接口,主要是根据参数和其他规则组装SQL,当然它提供BoundSql;BoundSql:建立SQL和参数的地方。我们一般修改SQL或者参数都是在BoundSql中修改的。对于BoundSql中如何实现多种参数的注入方式,我这儿就不讲解了。

既然有了SqlSessionFactory,那么我们很容易就得到SqlSession了。从Mapper映射器中,我们通过代理对象会进入到MapperMethod的execute方法。然后就能进入SqlSession的方法里了。我们需要了解的是SqlSession里的增删改查方法是如何实现的。

首先SqlSession下有四大对象。1、Executor执行器:用来调度StatementHandler、ParameterHandler、ResultHandler;2、StatementHandler:这个是在SqlSession里最重要的部分,它可以使数据库的Statement,即PreparedStatement执行操作(PreparedStatement接口是继承了Statement接口);3、ParamentHandler:用于SQL的参数处理;4、ResultHandler:用于最后返回数据集的封装。我学到这儿很疑惑这个Satement究竟是什么?Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存在的存储过程的调用。我们一般在插件中使用的是PrepareStatement,这三者对应了三种数据库会话器,SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler。对于着Executor也分为三种SIMPLE、REUSE、BATCH。关于参数处理器以及结果处理器就不提及了。

SqlSesion内部运行图

插件

插件部分,我无法总结清晰,所以给出我的分页插件中重点intercept函数实现的基本流程图。

intercept函数

本文主要是个人的一些总结,没有完全梳理MyBatis的流程等,也没有完全涉及MyBatis的所有知识。

上一篇 下一篇

猜你喜欢

热点阅读