/**
* Copyright 2009-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.keygen;
import java.sql.Statement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
/**
* @author Clinton Begin
*/
public interface KeyGenerator {
/**
* 执行之前运行
* @param executor
* @param ms
* @param stmt
* @param parameter
*/
void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
/**
* 执行之后运行
* @param executor
* @param ms
* @param stmt
* @param parameter
*/
void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
}
Jdbc3KeyGenerator
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.keygen;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.ArrayUtil;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
/**
* 主要用于数据库的自增主键,比如 MySQL、PostgreSQL;会将执行SQL后从Statemenet中获取主键放到参数对象对应的属性里
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class Jdbc3KeyGenerator implements KeyGenerator {
/**
* A shared instance.
*
* @since 3.4.3
*/
public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();
private static final String MSG_TOO_MANY_KEYS = "Too many keys are generated. There are only %d target objects. "
+ "You either specified a wrong 'keyProperty' or encountered a driver bug like #1523.";
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// do nothing
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
processBatch(ms, stmt, parameter);
}
/**
* 将 {@code stmt} 返回的主键赋值到 {@code parameter}
* @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param stmt 执行SQL 语句并返回它所生成结果的对象。
* @param parameter 参数对象
*/
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
/**
* keyProperties:
* MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,
* 默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
*/
final String[] keyProperties = ms.getKeyProperties();
//如果属性名数组为null 或者 属性名数组没有元素
if (keyProperties == null || keyProperties.length == 0) {
//结束方法
return;
}
/**
* getGeneratedKeys:该方法获取由于执行此Statement对象而创建的所有自动生成的键。
* 如果此Statement对象没有生成任何键,则返回空的ResultSet对象。
*/
try (ResultSet rs = stmt.getGeneratedKeys()) {
//获取结果集的元信息
final ResultSetMetaData rsmd = rs.getMetaData();
//获取mybatis全局配置信息
final Configuration configuration = ms.getConfiguration();
//如果结果集的返回列名数量小于配置属性名数组长度
if (rsmd.getColumnCount() < keyProperties.length) {
// Error? 不作任何处理
} else {
//根据 parameter 的类型构建AssignKey对象,然后将 rs 的结果赋值到 parameter 的元素中
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}
/**
* 根据 {@code parameter} 的类型构建AssignKey对象,然后将 {@code rs} 的结果赋值到 {@code parameter} 的元素中
* @param configuration mybatis全局配置新
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 属性名数组
* @param parameter 参数对象
*/
@SuppressWarnings("unchecked")
private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
Object parameter) throws SQLException {
//StrictMap,ParamMap:其功能甚至连代码都是一致的,都是HashMap的子类,都是对获取集合没有元素时会抛出异常。【个人认为是不是冗余了?】
//如果参数对象是StrictMap,ParamMap的实例时
if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
// Multi-param or single param with @Param
//根据 parameter 构建KeyAssigner对象,然后将rs的对应数据赋值到 parameter 的对应的元素中
assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map) parameter);
//如果参数对象是ArrayList实例,且parameter是有元素的 且 获取parameter的第一个元素属于ParamMap实例
} else if (parameter instanceof ArrayList && !((ArrayList>) parameter).isEmpty()
&& ((ArrayList>) parameter).get(0) instanceof ParamMap) {
// Multi-param or single param with @Param in batch operation
//构建AssignKey对象,将 rs 的结果赋值到 paramMapList 的元素中
assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, ((ArrayList>) parameter));
} else {
// Single param without @Param
//构建AssignKey对象,将 rs 的结果赋值到 parameter 的元素中,如果parameter不是集合,会自动将parameter转换成集合
assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
}
}
/**
* 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code parameter} 的元素中,如果parameter不是集合,会自动将parameter
* 转换成集合
* @param configuration mybatis全局配置信息
* @param rs 结果集
* @param rsmd 结果集元素
* @param keyProperties 属性名数组
* @param parameter 参数对象
* @throws SQLException
*/
private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Object parameter) throws SQLException {
//将parameter转换成Collection对象
Collection> params = collectionize(parameter);
//如果params是空集合
if (params.isEmpty()) {
//结束方法
return;
}
//定义一个分配者集合
List assignerList = new ArrayList<>();
//遍历属性数组
for (int i = 0; i < keyProperties.length; i++) {
//构建分配者对象饭后添加到分配者集合
assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
}
//获取参数对象的迭代器
Iterator> iterator = params.iterator();
//遍历结果集
while (rs.next()) {
//如果iterator没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
if (!iterator.hasNext()) {
//抛出异常,并描述
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
}
//获取下一个参数对象
Object param = iterator.next();
//变量分配者进行分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
assignerList.forEach(x -> x.assign(rs, param));
}
}
/**
* 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code paramMapList} 的元素中
* @param configuration mybatis全局配置新
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 配置的属性名数组
* @param paramMapList ArrayList类型的参数对象
* @throws SQLException
*/
private void assignKeysToParamMapList(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, ArrayList> paramMapList) throws SQLException {
//获取paramMapList的迭代器
Iterator> iterator = paramMapList.iterator();
//初始化一个分配器集合
List assignerList = new ArrayList<>();
//计数器,表示已分配的结果数
long counter = 0;
//遍历结果集
while (rs.next()) {
//如果ParamMapList没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
if (!iterator.hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
}
//获取参数对象的元素
ParamMap> paramMap = iterator.next();
//如果分配器集合为空
if (assignerList.isEmpty()) {
//遍历配置的属性数组
for (int i = 0; i < keyProperties.length; i++) {
//从ParamMap中构建KeyAssigner并赋值到新的entry中,然后将entry的值添加到分配器集合里
assignerList
.add(getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i], keyProperties, false)
.getValue());
}
}
//遍历分配器集合,将rs的对应columnPosition位置的列数据赋值到paramMap对应的propertyName中
assignerList.forEach(x -> x.assign(rs, paramMap));
counter++;
}
}
/**
* 根据 {@code paramMap} 构建KeyAssigner对象,然后将 {@code rs} 的对应数据赋值到 {@code paramMap} 的对应的元素中
* @param configuration Mybatis的全局配置信息
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 配置的属性名数组
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
*/
private void assignKeysToParamMap(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Map paramMap) throws SQLException {
//如果参数对象没有元素
if (paramMap.isEmpty()) {
//结束方法
return;
}
//新建一个分配映射集合
Map, List>> assignerMap = new HashMap<>();
//遍历属性名数组
for (int i = 0; i < keyProperties.length; i++) {
//从ParamMap中构建KeyAssigner并赋值到新的entry中
Entry entry = getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i],
keyProperties, true);
/**
* 下面代码与下面注释的代码的简化版:
*
* //获取entry的键名对应assignerMap的对象
* String key=entry.getKey();
* //初始化iteratorPair
* Entry, List> iteratoirPair=null;
* //如果key为null
* if(key==null){
* //获取paramMap对应key的值,并转换成Collection对象
* Object value=paramMap.get(key);
* Iterator iterator=collectionize(value).iterator();
* //初始化一个存储KeyAssigner集合
* List keyAssignerList=new ArrayList<>();
* //构成iterator实例
* iteratorirPair=enrty(iterator,keyAssignerList);
* }
*/
Entry, List> iteratorPair = assignerMap.computeIfAbsent(entry.getKey(),
k -> entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));
//将entry存储的keyAssigner存放到iteratorPair的集合里
iteratorPair.getValue().add(entry.getValue());
}
//计数器,表示已分配的结果数
long counter = 0;
//遍历结果集元素
while (rs.next()) {
//遍历assigenMap的值集合
for (Entry, List> pair : assignerMap.values()) {
//如果参数对象的键对象已经没有下一个了,这里的应该只是取iterator的第一个元素而已,而这里判断他是否存在第一个元素,不存在就抛出异常
if (!pair.getKey().hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
}
//获取下一个参数对象的健对象
Object param = pair.getKey().next();
//分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
pair.getValue().forEach(x -> x.assign(rs, param));
}
counter++;
}
}
/**
* 从ParamMap中构建KeyAssigner并赋值到新的entry中
* @param config Mybatis全局配置信息
* @param rsmd 结果集元信息
* @param columnPosition 列名位置
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
* @param keyProperty 配置的属性名
* @param keyProperties 配置的属性名数组
* @param omitParamName 是否忽略参数名称
*/
private Entry getAssignerForParamMap(Configuration config, ResultSetMetaData rsmd,
int columnPosition, Map paramMap, String keyProperty, String[] keyProperties, boolean omitParamName) {
//获取paramMap的值集合,再获取值集合的接口流对象,对值集合进行去重处理后,得到去重后的数量,如果去重后的数量为1,singleParam为true
//singleParam表示只有一个参数值
boolean singleParam = paramMap.values().stream().distinct().count() == 1;
//因为keyProperty有可能是'order.name'形式的,firstDot表示属性名的第一个点
int firstDot = keyProperty.indexOf('.');
//如果没有不存在第一个点
if (firstDot == -1) {
//如果只有一个参数值
if (singleParam) {
//从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
}
//如果不是只有一个参数值
throw new ExecutorException("Could not determine which parameter to assign generated keys to. "
+ "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
+ "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
+ paramMap.keySet());
}
//截取前面的字符串为参数名
String paramName = keyProperty.substring(0, firstDot);
//如果参数对象中有这个参数名
if (paramMap.containsKey(paramName)) {
//如果忽略参数名,aragParamName为null;否则aragPramName为singleParamName
String argParamName = omitParamName ? null : paramName;
//截取属性名点后面的字符串为参数键属性名
String argKeyProperty = keyProperty.substring(firstDot + 1);
//构建KeyAssigner并赋值到新的entry中
return entry(paramName, new KeyAssigner(config, rsmd, columnPosition, argParamName, argKeyProperty));
//如果只有一个参数值
} else if (singleParam) {
//从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
} else {
//如果参数对象中没有这个参数名且不只有一个参数值时
throw new ExecutorException("Could not find parameter '" + paramName + "'. "
+ "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
+ "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
+ paramMap.keySet());
}
}
/**
* 从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
* @param config Mybatis全局配置信息
* @param rsmd 结果集元信息
* @param columnPosition 列名位置
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
* @param keyProperty 配置的属性名
* @param omitParamName 是否忽略参数名称
*/
private Entry getAssignerForSingleParam(Configuration config, ResultSetMetaData rsmd,
int columnPosition, Map paramMap, String keyProperty, boolean omitParamName) {
// Assume 'keyProperty' to be a property of the single param. 假设关键属性的单一参数的属性。;
//获取paramMap唯一的键名
String singleParamName = nameOfSingleParam(paramMap);
//如果忽略参数名,aragParamName为null;否则aragPramName为singleParamName
String argParamName = omitParamName ? null : singleParamName;
//构建KeyAssigner并赋值到新的entry中,
return entry(singleParamName, new KeyAssigner(config, rsmd, columnPosition, argParamName, keyProperty));
}
/**
* 获取参数映射唯一健名
* @param paramMap 参数映射
* @return 参数映射唯一健名
*/
private static String nameOfSingleParam(Map paramMap) {
// There is virtually one parameter, so any key works.
//获取paramMap的键名Set,通过迭代器,获取第一个键名并返回
return paramMap.keySet().iterator().next();
}
/**
* 将 {@code param} 转换成 Collection对象
* @param param 参数对象
* @return 如果 {@code param} 不是Collection对象,都会转换成ArrayList对象;否则直接返回 {@code param} ;
*/
private static Collection> collectionize(Object param) {
//如果param本来就是Collection的实现类,
if (param instanceof Collection) {
//不需要转换,执行返回
return (Collection>) param;
//如果param是Object数组的实现了
} else if (param instanceof Object[]) {
//将param转换成ArrayList对象
return Arrays.asList((Object[]) param);
} else {
//如果是普通java类,构建成ArrayList对象
return Arrays.asList(param);
}
}
/**
* 构建Entry
* @param key 键名
* @param value 值对象
*/
private static Entry entry(K key, V value) {
// Replace this with Map.entry(key, value) in Java 9.
return new AbstractMap.SimpleImmutableEntry<>(key, value);
}
/**
* 键名分配者
*/
private class KeyAssigner {
/**
* mybatis全局配置信息
*/
private final Configuration configuration;
/**
* 结果集元信息
*/
private final ResultSetMetaData rsmd;
/**
* TypeHandler注册器
*/
private final TypeHandlerRegistry typeHandlerRegistry;
/**
* 列名位置
*/
private final int columnPosition;
/**
* 参数名
*/
private final String paramName;
/**
* 属性名
*/
private final String propertyName;
/**
* TypeHandler
*/
private TypeHandler> typeHandler;
/**
*
* @param configuration mybatis全局配置信息
* @param rsmd 结果集元信息
* @param columnPosition 列名位置
* @param paramName 参数名
* @param propertyName 属性名
*/
protected KeyAssigner(Configuration configuration, ResultSetMetaData rsmd, int columnPosition, String paramName,
String propertyName) {
super();
this.configuration = configuration;
this.rsmd = rsmd;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.columnPosition = columnPosition;
this.paramName = paramName;
this.propertyName = propertyName;
}
/**
* 分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
* @param rs 结果集
* @param param 参数对象
*/
protected void assign(ResultSet rs, Object param) {
//如果参数名不为null
if (paramName != null) {
// If paramName is set, param is ParamMap 如果设置了参数名称,参数是参数映射;
//从param获取paramName的值重新赋值给param
param = ((ParamMap>) param).get(paramName);
}
//构建param的元对象
MetaObject metaParam = configuration.newMetaObject(param);
try {
//如果typeHandler不为null
if (typeHandler == null) {
//如果param元对象存在propertyName的setter方法
if (metaParam.hasSetter(propertyName)) {
//获取propertyName的setter方法的属性类型
Class> propertyType = metaParam.getSetterType(propertyName);
//根据属性类型,当前列名位置的jdbc类型取得对应的TypeHandler对象并赋值给typeHandler
typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,
JdbcType.forCode(rsmd.getColumnType(columnPosition)));
} else {
//如果param元对象不存在propertyName的setter方法
throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"
+ metaParam.getOriginalObject().getClass().getName() + "'.");
}
}
//如果typeHandler还是为null
if (typeHandler == null) {
// Error? 忽略
} else {
//获取结果对象
Object value = typeHandler.getResult(rs, columnPosition);
//将结果对赋值到parm对应的propertyName中
metaParam.setValue(propertyName, value);
}
} catch (SQLException e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,
e);
}
}
}
}
SelectKeyGenerator
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.keygen;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
/**
* 用于执行selectKey标签的SQL,将结果赋值到参数对象对应的属性中
* @author Clinton Begin
* @author Jeff Butler
*/
public class SelectKeyGenerator implements KeyGenerator {
/**
* selectKeyId后缀
*/
public static final String SELECT_KEY_SUFFIX = "!selectKey";
/**
* 执行之前运行标记,通过这个标记使得keyStatement只执行一次
*/
private final boolean executeBefore;
/**
* selectKey的MappedStatement对象
*/
private final MappedStatement keyStatement;
/**
*
* @param keyStatement selectKey的MappedStatement对象
* @param executeBefore 业务SQL执行之前运行标记
*/
public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
this.executeBefore = executeBefore;
this.keyStatement = keyStatement;
}
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
//如果是业务SQL执行之前执行
if (executeBefore) {
//执行 ms 的SQL,然后将结果赋值 parameter 对应的配置属性中
processGeneratedKeys(executor, ms, parameter);
}
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
//如果不是业务SQL执行之前执行
if (!executeBefore) {
//执行 ms 的SQL,然后将结果赋值 parameter 对应的配置属性中
processGeneratedKeys(executor, ms, parameter);
}
}
/**
* 执行 {@code ms} 的SQL,然后将结果赋值 {@code parameter} 对应的配置属性中
* @param executor 执行器
* @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类,在这里指的select标签
* @param parameter 参数对象
*/
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
//如果参数对象不为null 且 selectKey的MappedStatement对象不为null 且 selectKey的配置的属性名不为null
if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
//获取selectKey配置的属性数组
String[] keyProperties = keyStatement.getKeyProperties();
//获取mybatis全局配置信息
final Configuration configuration = ms.getConfiguration();
//构建参数对象的元对象
final MetaObject metaParam = configuration.newMetaObject(parameter);
//如果属性数组不为null
if (keyProperties != null) {
// Do not close keyExecutor. 不要关闭KeyExecutor
// The transaction will be closed by parent executor. 事务会被关闭通过父级执行器
//新建一个SimpleExecutor对象,用于执行SQL
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
/**
* Executor.NO_RESULT_HANDLER: 表示没有结果处理器的标记
* RowBounds.DEFAULT:Mybatis的分页类的默认对象,表示从0条记录开始,到Integer.MAX_VALUE的最大记录数
*/
//执行查询SQL得到结果对象集合
List
NoKeyGenerator
/**
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.keygen;
import java.sql.Statement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
/**
* 什么事情都不干,里面是空实现方法
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class NoKeyGenerator implements KeyGenerator {
/**
* A shared instance.
* @since 3.4.3
*/
public static final NoKeyGenerator INSTANCE = new NoKeyGenerator();
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// Do Nothing
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// Do Nothing
}
}
动态代理代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。比如,现在存在一个UserService类:public class UserService { public void test() { System.out.println("test..."); }}此时,我们new一个UserService对象,然后执行test()方法,结果是
原文地址:http://www.cnblogs.com/Kavlez/p/4268601.html Enumeration
于Java 1.5增加的enum type...enum type是由一组固定的常量组成的类型,比如四个季节、扑克花色。在出现enum type之前,通常用一组int常量表示枚举类型。比如这样:
public static final int APPLE_FUJI = 0
第二章 Getting Started
1.Hive最大的局限性是什么?一是不支持行级别的增删改(insert, delete, update)二是查询性能非常差(基于Hadoop MapReduce),不适合延迟小的交互式任务三是不支持事务2. Hive MetaStore是干什么的?Hive persists table schemas and other system metadata.
/*
* 0.use a TwoWayLinkedList to store the path.when the node can't be path,you should/can delete it.
* 1.curSum==exceptedSum:if the lastNode is TreeNode,printPath();delete the node otherwise
//js获取项目根路径,如: http://localhost:8083/uimcardprj
function getRootPath(){
//获取当前网址,如: http://localhost:8083/uimcardprj/share/meun.jsp
var curWwwPath=window.document.locati
在Linux下面部 署应用的时候,有时候会遇上Socket/File: Can’t open so many files的问题;这个值也会影响服务器的最大并发数,其实Linux是有文件句柄限制的,而且Linux默认不是很高,一般都是1024,生产服务器用 其实很容易就达到这个数量。下面说的是,如何通过正解配置来改正这个系统默认值。因为这个问题是我配置Nginx+php5时遇到了,所以我将这篇归纳进