什么是Mybatis?

  Mybatis是一个半自动化的持久层框架。

  Mybatis可以将向PreparedStatement中的输入参数自动进行映射(输入映射),将结果集映射成Java对象(输出映射)

为什么使用Mybatis?

  JDBC:

    SQL夹杂在Java代码块中,耦合度高导致硬编码

    维护不易且实际开发需求中SQL有变化,频繁修改的情况多见

  Hibernate和JPA:

    长难复杂SQL,对于Hibernate而言处理也不容易

    内部自动生成的SQL,不容易做特殊优化

    基于全映射的全自动框架,大量字段的POJO进行部分映射时比较苦难,导致数据库性能下降

而实际开发中,对开发人员而言,核心SQL还是需要自己优化,而Mybatis中SQL和Java代码分开,功能边界清晰,一个专注业务,一个专注数据

配置文件,mybatis-config.xml

<?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>
<properties resource=""></properties><!--加载配置文件-->
<settings>
<!--开启二级缓存,默认开启-->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases> <!--设置单个pojo别名-->
<!--<typeAlias alias="Employee" type="com.yang.domain.Employee"/>-->
<!--对整个包下的pojo设置别名,别名为类名,如果类上使用了@Alias("")注解指定了别名则用注解设置的-->
<package name="com.yang.domain"/>
</typeAliases>
<!--与Spring整合后,environment配置将废除-->
<environments default="development">
<environment id="development">
<!--使用jdbc事务管理,由mybatis自己管理-->
<transactionManager type="JDBC"></transactionManager>
<!--数据库连接池,由mybatis自己管理-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="yang"/>
<property name="password" value="yang"/>
</dataSource>
</environment>
</environments>
<!--我们写的sql映射文件-->
<mappers>
<mapper resource="mybatis/xxxMapper.xml"/>
</mappers>
</configuration>

logback.xml,打印sql

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/logback/LogFile"/>
<!--控制台输出-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS}|%thread|%-5level|%r|%X{threadId}|%C|%msg%n</pattern>
</encoder>
</appender>
<!--sql相关-->
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

简单的Mybatis操作数据库步骤:

  1:创建Mybatis全局配置文件,包含了影响Mybatis行为的设置(setting)和属性(properties)信息、如数据库连接池信息等

  2:创建SQL映射文件,映射文件的作用就相当于是定义Dao接口的实现类如何工作

  3:将sql映射文件注册到全局配置中

  4:持久化代码

    1):根据全局配置文件得到SqlSessionFactory

    2):使用SqlSessionFactory,获取到SqlSession对象使用它来执行增删改查,一个SqlSession就是代表和数据库的一次会话,用完则关闭

    3):使用sql的唯一标志,namespace+id,执行sql

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2、获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、获取接口的实现类对象
//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
Employee employee = (Employee) openSession.selectOne(
"com.atguigu.mybatis.EmployeeMapper.selectEmp", 1);
} finally {
openSession.close();
}

第二种方式,接口式编程

  xxxMapper.xml中的namespace设置为xxxMapper接口的全路径名,Mybatis会为Mapper接口创建一个代理对象

  使用接口式编程会有更强的类型检查,参数控制等

 String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2、获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、获取接口的实现类对象
//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
} finally {
openSession.close();
}

SqlSession,需要注意:

  1、SqlSession的实例不是线程安全的,因此是不能被共享的

  2、SqlSession每次使用完成后需要正确关闭,这个关闭操作是必须的

  3、SqlSession可以直接调用方法的id进行数据库操作,不过一般推荐使用SqlSession获取到Dao接口的代理类,执行代理对象的方法,可以更安全的进行类型检查操作

代理Mapper执行方法的源码:

1、JDK动态代理创建Mapper的代理类

    public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
ClassLoader classLoader = mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{mapperInterface};
MapperProxy proxy = new MapperProxy(sqlSession);
return Proxy.newProxyInstance(classLoader, interfaces, proxy);
}

2、代理类执行方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else {
Class<?> declaringInterface = this.findDeclaringInterface(proxy, method);
MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, this.sqlSession);
Object result = mapperMethod.execute(args);
if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {
throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
} else {
return result;
}
}
}

execute:

    public Object execute(Object[] args) {
Object result = null;
Object param;
    // 判断执行sql类型,insert,update、delete或select,然后封装参数,调用的还是sqlSession的增删改查方法
if (SqlCommandType.INSERT == this.type) {
param = this.getParam(args);
result = this.sqlSession.insert(this.commandName, param);
} else if (SqlCommandType.UPDATE == this.type) {
param = this.getParam(args);
result = this.sqlSession.update(this.commandName, param);
} else if (SqlCommandType.DELETE == this.type) {
param = this.getParam(args);
result = this.sqlSession.delete(this.commandName, param);
} else {
if (SqlCommandType.SELECT != this.type) {
throw new BindingException("Unknown execution method for: " + this.commandName);
} if (this.returnsVoid && this.resultHandlerIndex != null) {
this.executeWithResultHandler(args);
} else if (this.returnsList) {
result = this.executeForList(args);
} else if (this.returnsMap) {
result = this.executeForMap(args);
} else {
param = this.getParam(args);
result = this.sqlSession.selectOne(this.commandName, param);
}
} return result;
}

getParam方法:

Mybatis的缓存:

  Mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能,Mybatis提供一级缓存,二级缓存

  一级缓存(粒度小):SqlSession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据,不同的SqlSession之间的缓

    存数据区域是互相不影响的。

    当第一次发起查询请求时,先去缓存中查找有没有符合的信息,如果没有,就从数据库中去查,然后将结果信息存储到一级缓存中

    如果SqlSession执行了Commit操作(插入、删除、更新)等,将清空SqlSession中的一级缓存,为了让缓存中的信息是最新信息,避免脏读,Mybatis默认是支持一级缓存的,

    关掉一级缓存的话需要在配置文件中配置。

    SqlSession关闭,一级缓存就清空

    应用:将Mybatis和Spring整合开发,事务控制是在service中,开始执行时,开启事务,创建SqlSession对象。

      在service方法内第一次调用,第二次调用将从一级缓存中取数据,方法结束,SqlSession关闭

      如果执行了两次service方法调用查询相同的信息,不走一级缓存,因为service方法结束,SqlSession就关闭了,一级缓存也随之清空

    

  二级缓存(粒度大):Mapper级别的缓存,多个SqlSession去操作同一个mapper sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

    多个SqlSession共享一个Mapper的二级缓存区域,按照namespace区分,每个mapper有都按自己的namespace区分的缓存区域。二级缓存默认是也是开启的

    开启二级缓存:

      1):在mybatis-config.xml配置文件的setting标签中设置二级缓存的开关

      2):在每个具体的mapper.xml文件中开启二级缓存

      3):调用pojo类实现序列化接口,因为为了将缓存数据取出执行反序列操作,因为二级缓存存储介质多种多样,不一定在内存

    禁用缓存:

      在每个select标签中设置useCache="false",如果想要针对每次查询都需要最新的数据,则需要设置禁用二级缓存

    

Mybatis和Spring整合:

  1)、需要Spring通过单例方式管理SqlSessionFactory,注入org.mybatis.spring.SqlSessionFactoryBean指定mybatis配置文件地址、dataSource、mapper.xml、别名等

  2)、Spring和Mybatis整合生成代理对象,使用SqlSessionFactory创建Session(整合自动完成),提供SqlSessionTemplate

  3)、持久层的mapper都需要由Spring进行管理

Mybatis原理及源码分析的更多相关文章

  1. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  2. ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...

  3. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  4. (转)ReentrantLock实现原理及源码分析

    背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...

  5. 【转】HashMap实现原理及源码分析

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...

  6. 【OpenCV】SIFT原理与源码分析:DoG尺度空间构造

    原文地址:http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度空间理论   自然界中的物体随着观测尺度不同有不同的表现形态.例如我们形 ...

  7. 《深入探索Netty原理及源码分析》文集小结

    <深入探索Netty原理及源码分析>文集小结 https://www.jianshu.com/p/239a196152de

  8. HashMap实现原理及源码分析之JDK8

    继续上回HashMap的学习 HashMap实现原理及源码分析之JDK7 转载 Java8源码-HashMap  基于JDK8的HashMap源码解析  [jdk1.8]HashMap源码分析 一.H ...

  9. 【OpenCV】SIFT原理与源码分析:关键点描述

    <SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一篇<方向赋值>,为找到的关键点即SI ...

随机推荐

  1. Spring源码解读--(一)源码下载

    走在Java程序员这条路上,网上Java各种工具满天飞,写个简单的CRUD,相信是个开发都能写出来,于是在思考如何可以在同行业中更有竞争力(其实就是如何赚更多钱).那么,老大给我推荐了Spring源码 ...

  2. python爬虫学习之路-遇错笔记-1

    当在运行爬虫时同时开启了Fidder解析工具时(此爬虫并不是用于爬取手机端那内容,而是爬去电脑访问的网页时),访问目标站点会遇到以下错误: File "C:\Users\litao\AppD ...

  3. EL表达式(二)运算符

    运算符"."和"[]": "."能做的"[]"也能做,"[]"能做的"."不一定 ...

  4. 让Debian以root登录

    Debian默认不允许root登录,所以修改之. (1)让Debian以root登录 修改gdm3的登录pam文件 #vi /etc/pam.d/gdm3 将auth required pam_suc ...

  5. Linux安装redis服务器和部署

    Linux安装redis和部署 第一步:下载安装包 wget http://download.redis.io/releases/redis-5.0.5.tar.gz 访问https://redis. ...

  6. Python3数据科学入门与实践学习教程

      整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看的时候可以关注下面几点: 1.为了追求精 ...

  7. MyBatis-Spring的sqlSessionTemplate

    转自:http://www.cnblogs.com/yhtboke/p/5611375.html SqlSessionTemplate SqlSessionTemplate是MyBatis-Sprin ...

  8. js实现千位符分隔

    前几天面试做保险项目的公司,被问到了一道实现千位符分割方法的题,乍一看挺简单,但做起来最后却没给出来一个合适的解决方法.回来自己琢磨了一个还行的答案. var num = 3899000001, ar ...

  9. jvm性能监控(5)-jdk自带工具 VisualVM

    一.在服务器的jdk的bin目录下添加配置文件 jstatd.all.policy [root@localhost /]# cd /usr/local/src/jdk1.8.0_131/bin/ [r ...

  10. k8s nginx ingress配置TLS

    在没有配置任何nginx下,k8s的nginx默认只支持TLS1.2,不支持TLS1.0和TLS1.1 默认的 nginx-config(部分可能叫 nginx-configuration)的配置如下 ...