浩哥解析MyBatis源码(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6709157.html
1、回顾
上一篇研究的是类型别名注册器TypeAliasRegister,它主要用于将基本类型和用户自定义的类型进行别名注册,将别名及其对应类类型保存在一个HashMap中,方便存取,是映射器映射功能实现的基础,本篇所研究的类型处理器注册器TypeHandlerReister是用来统筹管理类型处理器的,类型处理器是真正用于进行java类型与数据库类型映射的工具。
这一篇我们还是重点研究类型处理器的注册器,有关具体类型处理器的研究放到之后进行。
2、类型处理器
为了研究类型处理器注册器,我们需要对类型处理器有一定的基础和认识,这里简单介绍一下,具体内容可等下一篇。
类型处理器简单点说就是用于处理javaType与jdbcType之间类型转换用的处理器,MyBatis针对诸多Java类型与数据库类型进行了匹配处理。
它主要用于映射器配置文件的工作,在通过类型别名注册器获取类型别名代表的类型之后,就可以使用获取的类型通过类型处理器注册器来得到其对应的JdbcType和对应的类型处理器。
由此可见每个类型处理器都针对两个类型,一个Java类型,一个数据库类型。而类型处理器的作用就是进行二者之间的匹配、对应、转换。
3、类型处理器注册器
类型处理器注册器既能完成类型处理器的注册功能,同时也能对类型处理器进行统筹管理,其内部定义了集合来进行类型处理器的存取,同时定义了存取方法。
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();
以上是TypeHandlerRegister中定义的三个Map集合,这三个集合是用来保存类型处理器的注册信息的。
第一种:JDBC_TYPE_HANDLER_MAP,这是一个枚举Map集合,其内部是以JdbcType枚举类中枚举值为键创建的一种集合,这种集合先天存在键(枚举值),它是以数据库类型为键来保存类型处理器,亦即将类型处理器注册到对应的数据库类型上。
第二种:TYPE_HANDLER_MAP,这是一个前套Map集合,内层集合是以数据库类型为键保存处理器,外层集合为以Java类型来保存对应的数据库类型及其处理器,这个集合将三者联系起来,是真正进行三者对应关系匹配的集合。
第三种:ALL_TYPE_HANDLERS_MAP,这个集合中保存着所有的类型处理器,是以类型处理器的类类型为键值保存的,它可以统筹所有的类型处理器(带有统计的效果)。
3.1 基础类型处理器
在创建类型处理器注册器的时候,在其无参构造器中会进行基础类型处理器的注册,这些注册包括三种方式,一种是将以JavaType为键的保存方式,一种是以JdbcTye为键的保存方式,还有一种就是以JavaType与JdbcType为键的保存方式,这最后一种保存方式是一种嵌套的Map集合,前面的两种只是简单的Map集合。
下面将该无参构造器源码罗列:
//构造函数里注册系统内置的类型处理器
public TypeHandlerRegistry() {
//以下是为多个类型注册到同一个handler
register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler()); register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler()); register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler()); register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler()); register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler()); register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler()); register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler()); //以下是为同一个类型的多种变种注册到多个不同的handler
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler()); register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler()); register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler()); register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler()); register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler()); register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER); register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler()); register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler()); // issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
通过源码可以发现:MyBatis内置注册的类型处理器很是全面,几乎囊括了所有常用的类型,所以一般情况下我们直接使用内置的类型处理器进行类型处理即可。
3.1.1 针对JavaType,MyBatis内置注册了一下类型:
| 序号 | javaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | Boolean.class | null | BooleanTypeHandler | 入口2 | |
| 2 | boolean.class | null | BooleanTypeHandler | ||
| 3 | Byte.class | null | ByteTypeHandler | ||
| 4 | byte.class | null | ByteTypeHandler | ||
| 5 | Short.class | null | ShortTypeHandler | ||
| 6 | short.class | null | ShortTypeHandler | ||
| 7 | Integer.class | null | IntegerTypeHandler | ||
| 8 | int.class | null | IntegerTypeHandler | ||
| 9 | Long.class | null | LongTypeHandler | ||
| 10 | long.class | null | LongTypeHandler | ||
| 11 | Float.class | null | FloatTypeHandler | ||
| 12 | float.class | null | FloatTypeHandler | ||
| 13 | Double.class | null | DoubleTypeHandler | ||
| 14 | double.class | null | DoubleTypeHandler | ||
| 15 | String.class | null | StringTypeHandler | ||
| 16 | BigDecimal.class | null | BigDecimalTypeHandler | ||
| 17 | BigInteger.class | null | BigIntegerTypeHandler | ||
| 18 | Byte[].class | null | ByteObjectArrayTypeHandler | ||
| 19 | byte[].class | null | ByteArrayTypeHandler | ||
| 20 | Object.class | null | UNKNOWN_TYPE_HANDLER | ||
| 21 | Date.class | null | DateTypeHandler | ||
| 22 | java.sql.Date.class | null | SqlDateTypeHandler | ||
| 23 | java.sql.Time.class | null | SqlTimeTypeHandler | ||
| 24 | Character.class | null | CharacterTypeHandler | ||
| 25 | char.class | null | CharacterTypeHandler | ||
| 26 | java.sql.Timestamp.class | null | SqlTimestampTypeHandler |
3.1.2 针对JdbcType,MyBatis内置注册了一下类型:
| 序号 | javaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | JdbcType.BOOLEAN | BooleanTypeHandler | 入口1 | ||
| 2 | JdbcType.BIT | BooleanTypeHandler | |||
| 3 | JdbcType.TINYINT | ByteTypeHandler | |||
| 4 | JdbcType.SMALLINT | ShortTypeHandler | |||
| 5 | JdbcType.INTEGER | IntegerTypeHandler | |||
| 6 | JdbcType.FLOAT | FloatTypeHandler | |||
| 7 | JdbcType.DOUBLE | DoubleTypeHandler | |||
| 8 | JdbcType.CHAR | StringTypeHandler | |||
| 9 | JdbcType.VARCHAR | StringTypeHandler | |||
| 10 | JdbcType.CLOB | ClobTypeHandler | |||
| 11 | JdbcType.LONGVARCHAR | ClobTypeHandler | |||
| 12 | JdbcType.NVARCHAR | NStringTypeHandler | |||
| 13 | JdbcType.NCHAR | NStringTypeHandler | |||
| 14 | JdbcType.NCLOB | NClobTypeHandler | |||
| 15 | dbcType.ARRAY | ArrayTypeHandler | |||
| 16 | JdbcType.BIGINT | LongTypeHandler | |||
| 17 | JdbcType.REAL | BigDecimalTypeHandler | |||
| 18 | JdbcType.DECIMAL | BigDecimalTypeHandler | |||
| 19 | JdbcType.NUMERIC | BigDecimalTypeHandler | |||
| 20 | JdbcType.LONGVARBINARY | BlobTypeHandler | |||
| 21 | JdbcType.BLOB | BlobTypeHandler | |||
| 22 | JdbcType.OTHER | UNKNOWN_TYPE_HANDLER | |||
| 23 | JdbcType.TIMESTAMP | DateTypeHandler | |||
| 24 | JdbcType.DATE | DateOnlyTypeHandler | |||
| 25 | JdbcType.TIME | TimeOnlyTypeHandler |
3.1.3 针对JdbcType和JavaType,MyBatis内置注册了一下类型:
| 序号 | JavaType | JdbcType | TypeHandler | 入口 | 说明 |
| 1 | Date.class | JdbcType.DATE | DateOnlyTypeHandler | 入口3 | |
| 2 | Date.class | JdbcType.TIME | TimeOnlyTypeHandler | ||
| 3 | Object.class | JdbcType.OTHER | UNKNOWN_TYPE_HANDLER | ||
| 4 | byte[].class | JdbcType.BLOB | BlobTypeHandler | ||
| 5 | byte[].class | JdbcType.LONGVARBINARY | BlobTypeHandler | ||
| 6 | Byte[].class | JdbcType.BLOB | BlobByteObjectArrayTypeHandler | ||
| 7 | Byte[].class | JdbcType.LONGVARBINARY | BlobByteObjectArrayTypeHandler | ||
| 8 | String.class | JdbcType.CHAR | StringTypeHandler | ||
| 9 | String.class | JdbcType.CLOB | ClobTypeHandler | ||
| 10 | String.class | JdbcType.VARCHAR | StringTypeHandler | ||
| 11 | String.class | JdbcType.LONGVARCHAR | ClobTypeHandler | ||
| 12 | String.class | JdbcType.NVARCHAR | NStringTypeHandler | ||
| 13 | String.class | JdbcType.NCHAR | NStringTypeHandler | ||
| 14 | String.class | JdbcType.NCLOB | NClobTypeHandler |
3.2 注册入口方法
通过观察源码我们也可以发现这三种注册方式,我在这里将这三种方式的register方法看做三个入口,分别起名为:入口1、入口2、入口3。
其中:
入口1:对应之前介绍的第一种集合(枚举集合),其入口方法为:
//入口1
public void register(JdbcType jdbcType, TypeHandler<?> handler) {
JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
}
该入口方法用于将类型处理器注册到对应的数据库类型。
入口2:对应之前介绍的第二种嵌套集合(其中内层集合的键为null),其入口方法为:
//入口2
public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
register((Type) javaType, typeHandler);
}
该入口方法用于将类型处理器注册到对应的Java类型。
入口3:对应之前介绍的第二种嵌套集合,其入口方法为:
//入口3
public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
register((Type) type, jdbcType, handler);
}
该入口方法用于将类型处理器与Java类型和数据库类型联系起来。
上述的三个入口方法均是对内而设的入口方法,也就是说是用于注册器内部基础类型处理器(MyBatis内置的类型处理器)注册使用的。而MyBatis还提供了自定义类型处理器的功能,也就是说在该类中还提供了对外的自定义类型处理器注册入口。
这么理解:对内就是该方法被类内部调用进行注册,对外就是该方法被类外部的其他类进行调用而进行注册,这里的其他类其实就是XMLConfigBuilder类,它在构建Configuration对象时就会调用对外的注册方法,来将用户自定义的类型处理器注册到注册器中。
对外入口1:只指定包名的情况下,这种情况一般需要配合注解@MappedTypes使用,使用该注解进行JavaType的设置(即注解的value值)
//对外入口1:扫描器
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
//Ignore inner classes and interfaces (including package-info.java) and abstract classes
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type);
}
}
}
这个入口是一个扫描器,它会使用ResolverUtil工具类在给定包名下扫描所有类,然后进行循环注册,注册之前会进行排除操作,将内部类、接口、抽象类排除在外。这个扫描器针对的就是我们自定义的类型处理器进行注册,这个入口方法会在构建Configuration配置类时由XMLConfigBuilder进行调用,用于将用户自定义的类型处理器注册到注册器中。
上面的入口是在指定包名的情况下进行包扫描来获取包下所有类来进行类型处理器注册,一般会配合注解一起使用,但是如果不配合注解也能成功。如果配合注解指定JavaType,那么它将与对外入口2的情况一致(指定JavaType与TypeHandler),如果没有配合注解,那么就只有TypeHandler,这时候会调用另外一个注册方法,在这个方法中会再次验证是否存在注解,不存在的话,那么验证获取的类是否是TypeReference接口的实现类,如果是其实现类,说明这个类是一个类型处理器,那么再次调用另外一个注册方法,以该类型处理器的原生类型为参数进行调用,在这个方法中需要查询该类型处理器是否有注解@MappedJdbcTypes来指定JdbcType,如果有则以此JdbcType值为数据库类型,如果没有或者是Null类型,则直接将JdbcType置null再调用核心注册方法,将该类型处理器注册到TYPE_HANDLER_MAP集合中,最后还有将该注册器注册到ALL_TYPE_HANDLERS_MAP中用于统一管理。
对外入口2:指定Java类型与类型处理器的情况
//对外入口2
public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
}
对于第二种对外入口其实在第一种的情况中已经有所描述,这个方法会调用另外一个注册方法,来使用@MappedJdbcTypes获取jdbcType类型,其余步骤同上。
对外入口3:指定JavaType、JdbcType、TypeHandler三者的情况
//对外入口3
public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
}
这种情况可以直接调用核心注册进行注册即可。
对外入口4:只指定TypeHandler的情况
//对外入口4
public void register(Class<?> typeHandlerClass) {
boolean mappedTypeFound = false;
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class<?> javaTypeClass : mappedTypes.value()) {
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
if (!mappedTypeFound) {
register(getInstance(null, typeHandlerClass));
}
}
这种情况下,需要先验证是否有@MappedType指定JavaType,再验证是否有@MappedJdbcType指定JdbcType,分各种情况进行考虑,这在第一个入口方法中已经描述。
3.3 核心注册方法
虽然拥有诸多对内对外的注册入口方法,但是几乎都会指向核心注册方法,只有对内入口1不会指向核心注册方法,因为第一种对内入口方法的执行效果是往枚举集合JDBC_TYPE_HANDLER_MAP中注册数据库类型处理器。这与其他的注册情况不同,一般我们的注册是指往TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中注册类型处理器。
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
if (map == null) {
map = new HashMap<JdbcType, TypeHandler<?>>();
TYPE_HANDLER_MAP.put(javaType, map);
}
map.put(jdbcType, handler);
}
ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
}
然我来总述一下注册的过程,对上面的情况作何总结:
注册就是要三者兼备,哪三者:javaType、JdbcType、TypeHandler三者兼备,针对自定义类型处理器而言,我们可以通过继承BaseTypeHandler抽象类或者实现TypeHandler接口的方式来进行类型处理器的自定义实现。但是为了使其能在MyBatis中发挥作用,我们要将其注册到类型处理器注册器中。通过简单的配置即可实现,配置方式有两种:
<typeHandlers>
<package name="com.xx.xx"/>
<typeHandler handler="com.xx.xx.XxxTypeHandler" javaType="xxx" jdbcType="JdbcType.xxx" />
</typeHandlers>
若是用第二种方式配置即可直接进行注册,但是有时我们会省去javaType设置,而使用@MappedTypes注解来指定多个JavaType,或者省去JdbcType配置,采用@MappedJdbcTypes注解来指定多个jdbcType(毕竟配置文件只能指定一个,当需要设置多个时,就只能采用注解的方式实现),这时就需要查询目标处理器类的注解来获取类型,如果既没有在配置文件中配置,也没有通过注解配置,那么就只能置为null(这种情况毕竟,少见,一般我们要自定义类型处理器,必定是有某种类型处理器处理的不满意,我们肯定会指定对应的Java类型与数据库类型,如果听之任之的话我们又何必多此一举呢?)
极端情况就是采用包名配置或者只指定处理器类型进行注册,这时需要逐步查看类型处理器类的注解配置来获取该处理器处理的Java类型与数据库类型,最后在双方都获取到的情况下,三者齐备,调用核心注册方法,将这个类型处理器注册到TYPE_HANDLER_MAP嵌套集合和ALL_TYPE_HANDLERS_MAP集合中。
浩哥解析MyBatis源码(九)——Type类型模块之类型处理器注册器(TypeHandlerRegistry)的更多相关文章
- 浩哥解析MyBatis源码(八)——Type类型模块之TypeAliasRegistry(类型别名注册器)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6705769.html 1.回顾 前面几篇讲了数据源模块,这和之前的事务模块都是enviro ...
- 浩哥解析MyBatis源码(十)——Type类型模块之类型处理器
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...
- 浩哥解析MyBatis源码(十二)——binding绑定模块之MapperRegisty
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6758456.html 1.回顾 之前解析了解析模块parsing,其实所谓的解析模块就是为 ...
- 浩哥解析MyBatis源码(二)——Environment环境
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6625612.html 本应该先开始说Configuration配置类的,但是这个类有点过于 ...
- 浩哥解析MyBatis源码(四)——DataSource数据源模块
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6634880.html 1.回顾 上一文中解读了MyBatis中的事务模块,其实事务操作无非 ...
- 浩哥解析MyBatis源码(五)——DataSource数据源模块之非池型数据源
1 回顾 上一篇中我解说了数据源接口DataSource与数据源工厂接口DataSourceFactory,这二者是MyBatis数据源模块的基础,包括本文中的非池型非池型数据源(UnpooledDa ...
- 浩哥解析MyBatis源码(六)——DataSource数据源模块之池型数据源
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675674.html 1 回顾 上一文中解读了MyBatis中非池型数据源的源码,非池型也 ...
- 浩哥解析MyBatis源码(十一)——Parsing解析模块之通用标记解析器(GenericTokenParser)与标记处理器(TokenHandler)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6724223.html 1.回顾 上面的几篇解析了类型模块,在MyBatis中类型模块包含的 ...
- 浩哥解析MyBatis源码(七)——DataSource数据源模块之托管数据源
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675700.html 1 回顾 之前介绍的非池型与池型数据源都是MyBatis自己定义的内 ...
随机推荐
- 计算机存储负数以及int转byte时-128的出现
我们看下面这段代码 输出的结果的是128,这个没什么疑问 但是当我们不改变数值仅仅加了一个强制转换后 这时我们会发现结果会变成负的128.这时候我们就要怀疑了,为什么会出现这样的结果呢? 对于这个问题 ...
- linux 压缩zip包
压缩: zip -r 名称.zip 被压缩文件 解压: unzip 名称.zip
- .NET MD5加密解密代码
MD5简介: 是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数).不管是MD2.MD4还是MD5,它们都需要获 ...
- 右键打开cmd命令出错
今天想在E盘git clone一个工程项目下来,发现自己的window10上,出现了如下问题(不知道是不是是什么软件引起的冲突) 在度娘里面找了半天也没有解决问题,只有通过如下方法实现了 ctrl+r ...
- sqlplus入门使用
1.如果在PL/SQL 等工具里打开的话,直接修改下面的代码中[斜体加粗部分]执行 2.确保路径存在,比如[D:\oracle\oradata\Oracle9i\]也就是你要保存文件的路径存在 /*分 ...
- js 的DOM操作 2017-03-21
DOM(document object model) 文档对象模型 BOM(browse object model) 针对浏览器(如:弹出的窗口,滚动条等) 一.操作对象(注意大小写:注意elemen ...
- iOS 组件化
iOS 组件化介绍 随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分.但是仅仅完成代码拆分还不足以解决业务之间 ...
- Angular4.0.0正式版发布
来源于angular4.0.0发布时的公告,译者:niithub 原文发布时间:Thursday, March 23, 2017 翻译时间:2017年3月24日 angular4.0.0正式版现在可以 ...
- fastjson升级版本遇到的问题
前面的话: 有关阿里的fastjson升级时遇到的问题,链接如下 https://github.com/alibaba/fastjson/wiki/enable_autotype 我要说的,是我碰到这 ...
- windos环境apache+mysql+php+Discuz的安装配置
首先是相关软件的下载:PHP.Apache和Mysql软件以及VC库.相关软件可到我的百度网盘下载,百度网盘:http://pan.baidu.com/s/1o6DYcMu 相关软件的直接下载地址: ...