MyBatis进阶(一)运行原理
初次学习MyBatis,自己花了不少时间,理解一件事物是需要时间的。经过多次反复的理解,你的认知能力就可以得到提升。以下是学习MyBatis的一些理解认识,技术理解上若有不当之处,敬请朋友们提出宝贵意见,以此共勉!
感触:要想真正理解框架,应该深入到底层实现代码中去。只有这样,才能够真正理解其框架内涵,或许还可以写出个性化的框架喲!
基本的演变流程为:JDBC--->dbutils--->MyBatis--->Hibernate
MyBatis作为数据库持久层框架,在使用前首先导入相关jar包(mybatis-3.2.7.jar),还要对其进行配置,配置文件为mybatis.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="jdbc.properties" />
- <!-- 设置信息元素
- 会修改MyBatis在运行时的行为方式 -->
- <settings>
- <!-- 全局映射器启用缓存 -->
- <setting name="cacheEnabled" value="true" />
- <!-- 查询时,关闭关联对象及时加载以提高性能 -->
- <setting name="lazyLoadingEnabled" value="true" />
- <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指定),不会加载关联表的所有字段,以提高性能 -->
- <setting name="aggressiveLazyLoading" value="false" />
- <!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
- <setting name="multipleResultSetsEnabled" value="true" />
- <!-- 允许使用列标签代替列名 -->
- <setting name="useColumnLabel" value="true" />
- <!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
- <setting name="useGeneratedKeys" value="true" />
- <!-- 给予被嵌套的resultMap以字段-属性的映射支持 -->
- <setting name="autoMappingBehavior" value="FULL" />
- <!-- 对于批量更新操作缓存SQL以提高性能 -->
- <setting name="defaultExecutorType" value="BATCH" />
- <!-- 数据库超过25000秒仍未响应则超时 -->
- <setting name="defaultStatementTimeout" value="25000" />
- </settings>
- <!--
- 第一种写法
- 类型别名是为Java类型命名一个短的名字。它只和XML配置有关,只用来减少类完全限定名的多余部分
- <typeAliases>
- <typeAlias alias="Person" type="com.msun.daomain.Person"/>
- </typeAliases>
- -->
- <!-- 第二种写法 配合注解使用,在该包com.msun.daomain下使用注解@Alias("person")
- 指定一个包中所有类的别名-->
- <typeAliases>
- <package name="com.msun.daomain"/>
- </typeAliases>
- <!--
- development:开发模式
- work:工作模式
- -->
- <environments default="development" >
- <environment id="development" >
- <transactionManager type="JDBC" />
- <!-- JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始
- 连接和认证时间。这是一种当前Web应用程序用来快速响应请求很流行的方法。 -->
- <dataSource type="POOLED" >
- <property name="driver" value="${driver}"/>
- <property name="url" value="${url}"/>
- <property name="username" value="${username}"/>
- <property name="password" value="${password}"/>
- </dataSource>
- </environment>
- </environments>
- </configuration>
以上是对MyBatis的属性进行配置及设置JDBC连接对象的数据源连接池的实现。
- @Override
- public void insertUser(JSONObject user) {
- SqlSession session = null;
- try {
- //根据 JDBC 规范建立与数据库的连接;
- session = sqlSessionFactory.openSession();
- //通过反射打通 Java 对象与数据库参数交互之间相互转化关系
- UserMapper mapper = session.getMapper(UserMapper.class);
- mapper.insertUser(parasJson(user));
- session.commit();
- } finally {
- session.close();
- }
- }
以上代码完成数据写入数据库的操作。
其向外提供生成代理对象的函数getMapper()方法如下:
- public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
- //如果不存在这个mapper,则直接抛出异常
- if (!knownMappers.contains(type))
- throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
- try {
- //返回代理类
- return MapperProxy.newMapperProxy(type, sqlSession);
- } catch (Exception e) {
- throw new BindingException("Error getting mapper instance. Cause: " + e, e);
- }
- }
MyBatis中涉及到ORM的思想,ORM框架最重要功能是将面向对象方法中的对象和关系型数据库中的表关联了起来,在关联过程中就必然涉及到对象中的数据类型(Java数据类型)和数据库中的表字段类型的转换,Mybatis中的org.apache.ibatis.type包主要就是实现这个功能。只要提供了持久化类与表的映射关系,ORM框架在运行时就能参照映射文件的信息,把对象持久化到数据库中。当前ORM框架主要有三种:Hibernate,iBATIS,EclipseLink。
映射关系体现在mapper文件中,有两种方式进行关联,分别是:基于注解的方式和编写映射文件(xml)的形式。基于注解的形式如下:
- public interface UserMapper {
- @Select(value="select * from user where id = #{id}")
- public User findUserById(int id);
- @Select(value="select * from user where username = #{username} and password = #{password}")
- public User login(User user);
- @Insert(value="insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})")
- public void insertUser(User user);
- @Select(value="select * from user where nickname = #{nickname} and email = #{email}")
- public User findUserByNameAndEmail(User user);
- }
以插入操作为例,插入的数据为#{id}...其属性为domain域中类的相关属性。框架会在属性中进行相应属性的查找。若查找不到则会报错。
- public class SqlSessionUtils {
- /**
- * SqlSessionFactory对象可以看成DataSource(数据库连接池)
- * 在应用执行期间,应该只创建一次,建议使用单例模式
- */
- private static SqlSessionFactory factory=null;
- public static SqlSessionFactory getSessionFactory(){
- if(factory==null){
- synchronized (SqlSessionUtils.class) {
- if(factory==null){
- try {
- //1.创建配置文件的输入流
- String resource = "mybatis.xml";
- InputStream inputStream = Resources.getResourceAsStream(resource);
- //2.创建SqlSessionFactory
- factory=new SqlSessionFactoryBuilder().build(inputStream);
- //添加映射器类(注解方式),避免了对xml文件的依赖
- factory.getConfiguration().addMapper(MyLotteryMapper.class);
- factory.getConfiguration().addMapper(LotteryMapper.class);
- factory.getConfiguration().addMapper(UserMapper.class);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
- return factory;
- }
- }
在使用ibatis执行数据库访问时,会调用形如
- getSqlMapClientTemplate().queryForObject("getCityByCityId", cityId);
这样的代码。这样的形式要求调用方选择需要使用的函数(queryForObject、queryForList、update),还需要告诉这个函数具体执行哪一个statement(上文中是“getCityByCityId”),在这个过程中如果有一个地方选择错误或者拼写错误,不仅没有办法达到自己的期望值,可能还会出现异常,并且这种错误只有在运行时才能够发现。
mybatis对此进行了改进,只要先声明一个接口,就可以利用IDE的自动完成功能帮助选择对应的函数,简化开发的同时增加了代码的安全性。(如以下接口UserMapper所示 )
public interface UserMapper { @Select(value="select * from user where id = #{id}") public User findUserById(int id); @Select(value="select * from user where username = #{username} and password = #{password}") public User login(User user); @Insert(value="insert into user (id,username,phone,email,password) values(#{id},#{username},#{phone},#{email},#{password})") public void insertUser(User user); @Select(value="select * from user where nickname = #{nickname} and email = #{email}") public User findUserByNameAndEmail(User user); }
以下为MapperRegistry中addMapper方法的底层代码:
public void addMapper(Class<?> type) { //因为Java的动态代理只能实现接口,因而在注册mapper时也只能注册接口 if (type.isInterface()) { //如果已经注册过了,则抛出异常,而不是覆盖 if (knownMappers.contains(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { //先将这个mapper添加到mybatis中,如果加载过程中出现异常需要再将这个mapper从mybatis中删除 knownMappers.add(type); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. //下面两行代码其实做了很多的事,由于涉及的东西较多,在此不做过多的描述,留待以后专门进行介绍 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }

另外,MyBatis持久层框架还涉及到动态绑定、反射、单例、工厂设计模式。个人感觉,应深入到底层代码去阅读,只有这样才可以对框架有进一步的了解。
参考网址
http://www.th7.cn/Program/java/201407/240933.shtml http://www.th7.cn/Program/java/201407/240933.shtml
http://blog.csdn.net/hupanfeng/article/details/9238127 http://blog.csdn.net/hupanfeng/article/details/9238127
mybatis源代码分析之binding包
http://www.cnblogs.com/sunzhenchao/archive/2013/05/13/3075854.html http://www.cnblogs.com/sunzhenchao/archive/2013/05/13/3075854.html
Mybatis源代码分析之别名
http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3010527.html
动态代理 反射机制
java动态代理(JDK和cglib)
http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
http://www.cnblogs.com/sunzhenchao/tag/Mybatis/
Mybatis源代码分析之类型转换
http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3009431.html
MyBatis进阶(一)运行原理的更多相关文章
- Struts2进阶(一)运行原理及搭建步骤
Struts2进阶(一)运行原理 Struts2框架 Struts2框架搭建步骤 致力于web服务,不可避免的涉及到编程实现部分功能.考虑使用到SSH框架中的Struts2.本篇文章只为深入理解Str ...
- Mybatis的SqlSession运行原理
前言 SqlSession是Mybatis最重要的构建之一,可以简单的认为Mybatis一系列的配置目的是生成类似 JDBC生成的Connection对象的SqlSession对象,这样才能与数据库开 ...
- Web Service进阶(一)运行原理
利用清明小假期,温习了一遍Web Service的相关内容,对其工作原理进行了简要总结.以供有需求的朋友和自己日后参考.文章若有不当之处,敬请朋友们提出宝贵建议,以求共勉. Web服务中,我们应该首先 ...
- MyBatis温故而知新-底层运行原理
准备工作 public class MainClass { public static void main(String[] args) throws Exception { String resou ...
- 简述 Mybatis 的插件运行原理,以及如何编写一个插件?
Mybatis 仅可以编写针对 ParameterHandler.ResultSetHandler. StatementHandler.Executor 这 4 种接口的插件,Mybatis 使用 J ...
- 简述 Mybatis 的插件运行原理,以及如何编写一个插件。
Mybatis 仅可以编写针对 ParameterHandler.ResultSetHandler. StatementHandler.Executor 这 4 种接口的插件,Mybatis 使用 J ...
- mybatis运行原理
mybatis运行原理 运行过程中涉及到的类或者接口 Resources(c) :用于加载mybatis核心配置文件 XMLConfigBuilder(c) :用于解析xml文件(核心配置文件) Co ...
- 互联网轻量级框架SSM-查缺补漏第七天(MyBatis的解析和运行原理)
第七章MyBatis的解析和运行原理 SqlSessionFactory是MyBatis的核心类之一,其最重要的功能就是提供创建MyBatis的核心借口SqlSession,所以要先创建SqlSess ...
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
随机推荐
- Echarts 地图添加自定义区域
使用 Echarts 生成地图时,如果需要添加一些自定义区域,该怎么做呢?请看下面示例. 生成原始地图 index.hmtl 引入 Jquery 和 Echart <!DOCTYPE html& ...
- jquery传值与判断
js判断是否包含字符串 var str="Hello world!" var s = str.indexOf("Hello") 存在则s>-1不存在则是s ...
- java客户端Jedis操作Redis Sentinel 连接池
pom配置: <dependency> <groupId>org.springframework.data</groupId> <artifactId> ...
- C++框架_之Qt的开始部分_概述_安装_创建项目_快捷键等一系列注意细节
C++框架_之Qt的开始部分_概述_安装_创建项目_快捷键等一系列注意细节 1.Qt概述 1.1 什么是Qt Qt是一个跨平台的C++图形用户界面应用程序框架.它为应用程序开发者提供建立艺术级图形界面 ...
- Linux搭建lamp(Apache+PHP+Mysql环境)centos7.2版详细教程
我们更多的网站服务器是选择了Linux系统,这里建议你选择centos,这也是阿里云ecs推荐的系统,在服务器上比较推荐centos,特别对于新手,首选CentOS,并不是centos比Debian和 ...
- docker volume创建、备份、nfs存储
docker存储volume #环境 centos7.4 , Docker version 17.12.0-ce docker volume创建.备份.nfs存储 #docker volume 数据存 ...
- 使用WeihanLi.Redis操作Redis
WeihanLi.Redis Intro StackExchange.Redis 扩展,更简单的泛型操作,并提供一些的适用于业务场景中的扩展 基于 Redis 的五种数据类型扩展出了一些应用: Str ...
- Django Model field reference
===================== Model field reference ===================== .. module:: django.db.models.field ...
- Bootstrap3 排版-标题
HTML 中的所有标题标签,<h1> 到 <h6> 均可使用.另外,还提供了 .h1 到 .h6 类,为的是给内联(inline)属性的文本赋予标题的样式. h1. Boots ...
- Programming In Scala笔记-第二、三章
本系列博客以<Programming in Scala 2nd Edition>为主,围绕其中的代码片段进行学习和分析. 本文主要梳理Chapter2和Chapter3中涉及到的主要概念. ...