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机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
随机推荐
- 有些时候会看到url参数上出现%BF之类
这是URLDecoder和URLEncoder的原因 因为他们是参数,避免影响网页的连接跳转,再到了服务器的时候会自动转过来 当URL地址中仅包含普通非中文字符串和application/x-www- ...
- Angular 路由配置
路由,简单的来说就是让组件之间进行跳转和参数的传递. 1.先在app目录下创建一个名为app.route.ts的路由组件 2.打开app.route.ts 在里面创建路由组件的代码(可通过编辑器快捷生 ...
- 基于PHP的对接免费电子面单接口平台的案例-快宝开放平台
一.电子面单对接平台 电子面单对接平台分为两类: 1 .各大快递公司自有的电子面单接口开放平台:对接起来麻烦,需要每个快递公司分别调试接口,费时费力. 2 .第三方快递开放平台:如快宝开放平台(htt ...
- redis在java客户端的操作
redis高性能,速度快,效率高的特点,用来做缓存服务器是很不错的选择.(和memcache相似)redis在客户端的操作步骤: 1.redis单机版操作 1.1通过Jedis对象操作 (1)将安装r ...
- 初步配置阿里云ECS服务器
阿里云服务器配置记录01 购买阿里云学生服务器9.9元每月 创建ubuntu64位实例系统,注意必须添加安全组设置才可远程登入(设置课访问端口及IP范围 putty 软件在windows10下远程登入 ...
- 闭关修炼屯题中,期末考完A
FJUTOJ 1279 #include <cstdio> #include <iostream> #include <algorithm> #include &l ...
- JavaScript 知识图谱
- Python3 解释器
Linux/Unix的系统上,Python解释器通常被安装在 /usr/local/bin/python3.4 这样的有效路径(目录)里. 我们可以将路径 /usr/local/bin 添加到您的Li ...
- 用豆瓣镜像解决pip安装慢的问题
pip3 install django==1.9 -i http://pypi.douban.com/simple/
- iOS开源加密相册Agony的实现(七)
简介 虽然目前市面上有一些不错的加密相册App,但不是内置广告,就是对上传的张数有所限制.本文介绍了一个加密相册的制作过程,该加密相册将包括多密码(输入不同的密码即可访问不同的空间,可掩人耳目).Wi ...