- 浏览: 533949 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
rgqancy:
终于明白为啥XML里要带jdbcType=XXXX了。
mybatis 需要注意的点 MyBatis 插入空值时,需要指定JdbcType (201 -
rzh0001:
Thanks a lot
mybatis 需要注意的点 MyBatis 插入空值时,需要指定JdbcType (201 -
guji528:
学习了,谢谢
mybatis 需要注意的点 MyBatis 插入空值时,需要指定JdbcType (201 -
AKka:
彻底清楚这个错误的原因了。向楼主学习了。
mybatis 需要注意的点 MyBatis 插入空值时,需要指定JdbcType (201 -
远去的渡口:
武汉小吃,我最爱热干面和鸭脖,想念啊~~
过年时候还学习编程, ...
过年的心情
这篇博客是我学习mybatis的心得。也是对自己的鞭策。
这些我想一步步的解答:)每天记录一下自己的学习心得
如下代码:
首先 那我就看Resources这个类是如何解析资源的吧。
Resources 这个类 位于 org.apache.ibatis 包下面 包下面的类如下所示:
实际上是调用 ClassLoaderWrapper的getResourceAsReader方法
如下所示:
实际上调用的主要是:ClassLoaderWrapper的getResourceAsStream方法
在这里呢,我们发现classLoader 这里传入了多个classLoader 如下:
这里应该是为了防止找不到相应的配置文件而采取的措施
需要复习一下类的加载机制了。
JVM的类加载是通过ClassLoader以及其子类完成。
打印出传递的5个classLoader 发现结果如下:
发现后面三个classLoader是一样的 也就是System class loader
好了 现在已经得到配置文件 reader对象了 ,如下解析呢 看下一步
关键在于 SqlSessionFactoryBuilder这个类
这个时候需要看一看XMLConfigBuilder的代码
实际上 关键是 parseConfiguration 来解析这个节点
那么如何解析typeAliases节点呢?
看如下代码:
TypeAliasRegistry 类型命名注册的方法 : registerAlias
TypeAliasRegistry类里定义了一个hashMap
如:
这里调用核心的方法:
这里最关键的节点是: enviroment
那么数据工厂怎么来处理节点的参数呢?
主要的是方法factory.setProperties(props);
这里 我们可以看到 DataSourceFactory 有一个实现类UnpooledDataSourceFactory
如下代码实现:
这里的关键是一个MetaObject对象的用法。
如上代码: MetaObject可以为对象赋值某一个属性 username ,所以 111111
这里需要详细介绍一下:MapWrapper 以及 BeanWrapper两个类
这些我想一步步的解答:)每天记录一下自己的学习心得
如下代码:
String resource = "config/ibatis/configuration.xml"; Reader reader; try { reader = Resources.getResourceAsReader(resource); sessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); }
首先 那我就看Resources这个类是如何解析资源的吧。
Resources 这个类 位于 org.apache.ibatis 包下面 包下面的类如下所示:
实际上是调用 ClassLoaderWrapper的getResourceAsReader方法
如下所示:
public static Reader getResourceAsReader(String resource) throws IOException { Reader reader; if (charset == null) { //得到inputStreamReader reader = new InputStreamReader(getResourceAsStream(resource)); } else { reader = new InputStreamReader(getResourceAsStream(resource), charset); } return reader; }
实际上调用的主要是:ClassLoaderWrapper的getResourceAsStream方法
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) { for (ClassLoader cl : classLoader) { if (null != cl) { // try to find the resource as passed InputStream returnValue = cl.getResourceAsStream(resource); // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource if (null == returnValue) returnValue = cl.getResourceAsStream("/" + resource); if (null != returnValue) return returnValue; } } return null; }
在这里呢,我们发现classLoader 这里传入了多个classLoader 如下:
return getResourceAsStream(resource, new ClassLoader[]{ classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader(), ClassLoader.getSystemClassLoader() });
这里应该是为了防止找不到相应的配置文件而采取的措施
需要复习一下类的加载机制了。
引用
JVM的类加载是通过ClassLoader以及其子类完成。
打印出传递的5个classLoader 发现结果如下:
发现后面三个classLoader是一样的 也就是System class loader
好了 现在已经得到配置文件 reader对象了 ,如下解析呢 看下一步
关键在于 SqlSessionFactoryBuilder这个类
//============================= 上面是方法重载================================================== public SqlSessionFactory build(Reader reader, String environment, Properties props) { try { //通过XMLConfigBuilder 解析 这个类是解析 configuration.xml的关键 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, props); Configuration config = parser.parse(); return build(config); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { // 关闭 reader 所以不需要在程序中关闭 reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
这个时候需要看一看XMLConfigBuilder的代码
public XMLConfigBuilder(Reader reader, String environment, Properties props) { super(new Configuration()); //创建一个新的Configuration对象 ErrorContext.instance().resource("SQL Mapper Configuration"); this.configuration.setVariables(props); this.parsed = false; this.environment = environment; //创建xpath解析器,需要验证 主要是创建xml的document 便于引用 this.parser = new XPathParser(reader, true, new XMLMapperEntityResolver(), props); } //======================================= 以上三个构造方法(reader,environment,props) ==================================================== public Configuration parse() {// 解析xml if (parsed) {//若没有解析 则抛出异常 throw new BuilderException("Each MapperConfigParser can only be used once."); } parsed = true; //改变是否解析过的状态 //应该是查找configuration节点 然后开始解析配置 parseConfiguration(parser.evalNode("/configuration")); //将解析后的configuration后返回 return configuration; }
实际上 关键是 parseConfiguration 来解析这个节点
/** * 根据根节点来解析 * @param root * * <configuration> <!-- properties文件 --> <properties resource="config/properties/db.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${db.connection.driver_class}"/> <property name="url" value="${db.connection.url}"/> <property name="username" value="${db.connection.username}"></property> <property name="password" value="${db.connection.password}"></property> </dataSource> </environment> </environments> <mappers> <!-- 活动的sqlxml --> <mapper resource="config/ibatis/test.xml" /> </mappers> </configuration> */ private void parseConfiguration(XNode root) { try { typeAliasesElement(root.evalNode("typeAliases")); //注册别名 pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); propertiesElement(root.evalNode("properties")); //属性文件 settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); //解析environments节点 ,这里是非常关键的 typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers"));//解析mapper文件 } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
那么如何解析typeAliases节点呢?
看如下代码:
/** * 解析别名 * @param parent */ private void typeAliasesElement(XNode parent) { if (parent != null) { for (XNode child : parent.getChildren()) { String alias = child.getStringAttribute("alias"); //别名 String type = child.getStringAttribute("type"); //类的路径 try { Class clazz = Resources.classForName(type); //加载类 if (alias == null) { typeAliasRegistry.registerAlias(clazz); } else { typeAliasRegistry.registerAlias(alias, clazz); } } catch (ClassNotFoundException e) { throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e); } } } }
TypeAliasRegistry 类型命名注册的方法 : registerAlias
TypeAliasRegistry类里定义了一个hashMap
如:
private final HashMap<String, Class> TYPE_ALIASES = new HashMap<String, Class>();
这里调用核心的方法:
/** * 注册别名 * @param alias 别名的名称 需要放入map中 * @param value value 相当于类的class */ public void registerAlias(String alias, Class value) { assert alias != null; String key = alias.toLowerCase();//小写 if (TYPE_ALIASES.containsKey(key) && !TYPE_ALIASES.get(key).equals(value.getName()) && TYPE_ALIASES.get(alias) != null) { if (!value.equals(TYPE_ALIASES.get(alias))) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(alias).getName() + "'."); //已经存在映射关系,抛出异常 } } TYPE_ALIASES.put(key, value); }
这里最关键的节点是: enviroment
/** 解析environments节点 * <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${db.connection.driver_class}"/> <property name="url" value="${db.connection.url}"/> <property name="username" value="${db.connection.username}"></property> <property name="password" value="${db.connection.password}"></property> </dataSource> </environment> </environments> ***/ private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { //没有传递environment environment = context.getStringAttribute("default"); //得到default属性的名称 } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); //id属性 if (isSpecifiedEnvironment(id)) { //id是否和默认的eviroment相同 ,若相同 则进行比较 //当前是JDBC factory 以后还有其他的实现类 如下的方法解析transactionManager的节点 TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); //得到数据工厂 得到数据源 DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); //解析dataSource节点 Environment.Builder environmentBuilder = new Environment.Builder(id, txFactory, dsFactory.getDataSource()); configuration.setEnvironment(environmentBuilder.build()); } } } }
那么数据工厂怎么来处理节点的参数呢?
/** 解析 dataSource 元素 **/ private DataSourceFactory dataSourceElement(XNode context) throws Exception { if (context != null) { String type = context.getStringAttribute("type");//POOLED,UNPOLLED /**类似如下所示: * <dataSource type="POOLED"> <property name="driver" value="${db.connection.driver_class}"/> <property name="url" value="${db.connection.url}"/> <property name="username" value="${db.connection.username}"></property> <property name="password" value="${db.connection.password}"></property> 若是pooled可以有其他的属性 如最小的链接数 </dataSource> */ Properties props = context.getChildrenAsProperties(); DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance(); factory.setProperties(props); //设置属性 return factory; } throw new BuilderException("Environment declaration requires a DataSourceFactory."); }
主要的是方法factory.setProperties(props);
这里 我们可以看到 DataSourceFactory 有一个实现类UnpooledDataSourceFactory
如下代码实现:
/** 传入的参数是DataSource的配置项 **/ public void setProperties(Properties properties) { Properties driverProperties = new Properties(); MetaObject metaDataSource = MetaObject.forObject(dataSource); //可以代理的为对象添加属性 for (Object key : properties.keySet()) { String propertyName = (String) key; if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {//若属性名称是 以driver开头的 String value = properties.getProperty(propertyName); driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value); } else if (metaDataSource.hasSetter(propertyName)) { String value = (String) properties.get(propertyName);//得到dataSource的节点属性集合 Object convertedValue = convertValue(metaDataSource, propertyName, value); metaDataSource.setValue(propertyName, convertedValue); //此方法可以动态的调用set方法 很奇妙 ,明天继续看哈哈 } else { throw new DataSourceException("Unkown DataSource property: " + propertyName); } } if (driverProperties.size() > 0) { metaDataSource.setValue("driverProperties", driverProperties); } }
这里的关键是一个MetaObject对象的用法。
Author author = new Author(); MetaObject metaDataSource = MetaObject.forObject(author); metaDataSource.setValue("username","111111");
如上代码: MetaObject可以为对象赋值某一个属性 username ,所以 111111
这里需要详细介绍一下:MapWrapper 以及 BeanWrapper两个类
发表评论
-
四位计算机的原理及其实现
2015-09-05 19:23 942你是否想过,计算机为什么会加减乘除?或者更直接一点,计算机的原 ... -
ubuntu13.04安装mysql5.6RPM包1、使用的安装包MySQL-5.6.12-2.l
2014-11-20 23:08 1032ubuntu13.04安装mysql5.6 RPM包 1、 ... -
字典树相关代码
2014-08-10 18:21 1012package com.myway.study; i ... -
两有序数组求交集
2014-05-01 00:27 1082package com.myway.study; i ... -
JVM垃圾收集器异同
2014-04-22 09:48 1269VM 垃圾收集器有3类,这里主要介绍我们常用的 并行和并发收集 ... -
idea 11 如何实现热部署
2014-02-17 13:37 1044idea 如何配置 热部署呢? 如图: 然后配置 t ... -
java位操作符总结
2013-08-04 20:42 937二进制负数以它正值的 ... -
快速排序简要算法
2013-07-21 22:21 1112package math; import jav ... -
memcached安装
2013-03-10 09:32 4863今天 ,心血来潮 想安装下memcached 先给自己测试一下 ... -
温习温习 aop的原理
2013-02-11 22:23 1447在我工作这几年里,spring aop 用得最多的有两点 1 ... -
URL编码以及GET和POST提交乱码解决方案
2012-09-14 16:59 16971. 什么是URL编码。 ... -
Struts2 IF 判断 SESSION值
2012-08-16 15:12 1211<s:if test="ticke ... -
@me 如何处理
2012-07-28 22:37 1170红薯 分享了这个代码 ,我觉得很好 在这个社区与大家分享 。 ... -
mybatis 需要注意的点 MyBatis 插入空值时,需要指定JdbcType (201
2012-07-27 22:59 161803前天遇到一个问题 异常显示如下: 引用 Exception i ... -
猜测 javaye的分页设计
2012-07-05 21:32 1150非常喜欢javaeye的分页 ,自己也写了一个 按照逻辑测试了 ... -
java控制事务级别
2012-06-18 20:40 1171JDBC事务并发产生的问题和事务隔离级别 原子操作使用事务,一 ... -
ibatis / mybatis 存储过程调用 区别 以及例子
2012-06-11 21:16 1596ibatis: 如下: xml配置文件: 请看 ... -
java timerTask timer分析
2012-06-07 20:37 1571首先看一看 timer timerTask如何调用 ? ... -
ibatis 设置行级锁 操作
2012-04-07 18:46 3830在使用ibatis进行编程的时候 需要锁行的时候 我经常用存储 ... -
MapWrapper 学习
2012-01-04 16:25 1582MetaObject 有一个 setValue方法 这个方 ...
相关推荐
"MYBATIS学习资料文件"这一标题明确指出,这是一份与MyBatis相关的学习资源集合,可能包含教程、示例代码、笔记等,旨在帮助用户理解和掌握MyBatis这一流行的数据持久层框架。 【描述解读】 描述中提到“mybatis所...
【标题】"MyBatis学习笔记1" 涉及的知识点主要集中在MyBatis这一流行的持久层框架上。MyBatis是一个优秀的Java ORM(对象关系映射)框架,它允许开发者将SQL查询与Java代码分离,使得数据库操作更加灵活且易于维护。...
MyBatis 是一款优秀的...通过深入学习 MyBatis,你可以有效地将业务逻辑与数据访问层分离,提高代码的可维护性和可读性。同时,MyBatis 的灵活性和强大的功能使其成为 Java 开发者在处理 SQL 操作时的首选框架之一。
这篇“mybatis 学习笔记”将带你深入理解 MyBatis 的核心概念和主要功能。 1. **MyBatis 概述**: MyBatis 是一个轻量级的 Java ORM(对象关系映射)框架,它的核心是 SQL 映射文件和 SqlSessionFactory。ORM 技术...
在本篇【jee、spring、spring mvc、mybatis 学习(五)】中,我们将深入探讨四个关键的Java企业级开发技术:Java EE(Java Enterprise Edition)、Spring框架、Spring MVC以及MyBatis。这些技术是现代Java Web应用...
Mybatis学习笔记整理,全面详实,通俗易懂.md
本资源“MyBatis学习实例”旨在帮助你深入理解并掌握MyBatis的核心概念和实践应用。 1. **MyBatis概述** MyBatis是一个基于Java的持久层框架,它简化了数据库访问,通过XML或注解方式配置和映射原生信息,将接口和...
在这些MyBatis学习笔记中,我们可以期待涵盖以下几个关键知识点: 1. **MyBatis简介**:首先会介绍MyBatis的起源、目标和优点,例如简化数据库操作、提高开发效率、易于维护等。 2. **环境搭建**:包括如何下载...
MyBatis学习总结笔记 MyBatis是一个优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始...
本资源包含Mybatis的学习视频、教程以及源码,非常适合初学者和进阶者进行深入研究。 首先,Mybatis的学习视频将覆盖从基础到高级的各个主题,如Mybatis的安装配置、XML配置文件的理解、动态SQL的运用、Mapper接口...
在这个"Mybatis学习的demo工程"中,我们主要探讨以下几个关键知识点: 1. **MyBatis核心组件**:MyBatis的核心组件包括SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession和Mapper接口。...
### MyBatis学习笔记 #### 一、MyBatis简介及环境搭建 **MyBatis** 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis...
这份“MyBatis学习手册及配置文件”提供了全面的学习资源,帮助用户深入理解并掌握MyBatis的核心概念和实践技巧。 首先,`SqlMapConfig.xml`是MyBatis的全局配置文件,它是MyBatis启动时加载的第一个配置文件,用于...
在"mybatis学习1"中,`com.cpf`包下的源码可能涉及MyBatis的基本使用,包括Mapper接口的实现、动态SQL、结果映射等。Mapper接口允许开发者定义SQL查询,并通过方法签名与SQL结果进行匹配。动态SQL是MyBatis的一大...
在本学习资源中,你将找到一份详尽的Mybatis学习笔记和源码,这将极大地助力你的学习过程,尤其是对自学者而言。这份笔记被认为是非常有价值且深入的,作者在其中倾注了大量的精力,确保了内容的全面性和实用性。 ...
MyBatis是一款流行的Java持久层框架,它的设计理念是让程序员能够通过简单的配置和映射,将对象和数据库中的记录进行关联。MyBatis的主要特点是支持定制化SQL、存储过程以及高级映射,同时它减少了传统JDBC操作中...
本文将基于“Mybatis学习源代码”这一主题,深入探讨Mybatis的基本概念、核心功能以及如何通过狂神说的视频教程进行学习。 Mybatis是一个基于Java的持久层框架,它提供了一个SQL映射框架,可以将SQL语句与Java代码...
MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习代码MyBatis的学习...