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机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
随机推荐
- web项目部署到阿里云服务器步骤
http://www.cnblogs.com/qq3111901846/p/6178855.html http://blog.csdn.net/liona_koukou/article/details ...
- JS运行机制之 Event Loop 的思考
先举个栗子,如下: for (var i = 0; i < 5; i++) { setTimeout(function() { console.log('i: ',i); //一秒之后输出几乎没 ...
- vim基本操作
Vim 是 Linux 系统上的最著名的文本/代码编辑器,也是早年的 Vi 编辑器的加强版,而 gVim 则是其 Windows 版.它的最大特色是完全使用键盘命令进行编辑,脱离了鼠标操作虽然使得入门 ...
- ERP中的地区管理
地区管理 地区管理主要实现地区数据的添加.编辑.查看.启用.禁用等功能,另外还包含地区选择控件封装. 业务功能点: 地区数据查看:地区列表树状展现,列表增加省.市.区.县.乡图标. 地区选择控件:选择 ...
- Python中将一个对象倒序输出的4种方法
Python中将一个对象倒序输出的4种方法就用列表来举例说明吧: >>> lst = [1,2,3,4,5,6] #创建测试列表 #方法1: >>> lst.rev ...
- JConsole/JvisualVM 远程连接失败处理
今天在使用JConsole进行远程连接时,发现IP和端口在Windows下是可以远程telnet的,但是,使用JConsole时却无法连接. 我的环境如下: Windows下运行JConsole,准备 ...
- Java 读取Excel文件
https://www.cnblogs.com/wwzyy/p/5962076.html 先把上面的参考博客看了,如果会导入包的话,下面的教程就直接忽略emm 这时候,你应该把jar包下载 ...
- Go 语言函数
函数是基本的代码块,用于执行一个任务. Go 语言最少有个 main() 函数. 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务. 函数声明告诉了编译器函数的名称,返回类型,和参数. ...
- SpringBatch的核心组件JobLauncher和JobRepository
Spring Batch的框架包括启动批处理作业的组件和存储Job执行产生的元数据.因此只需掌握配置这个基础框架在批处理应用程序中即启动Jobs并存储Job元数据. 组件:Job Launcher和J ...
- java中static特殊性和final(static成员直接被访问,this不能用在static方法中,static不可访问非static)
java的static关键字 java中,static修饰的成员变量和成员方法叫静态变量和静态方法,不依赖类特定的实例,被类的所有实例共享. 静态变量或类变量 和 实例变量,区别是: 静态变量在内存中 ...