通用mapper生成sql及mybatis使用过程
sql装配,自己实现一个,通用mapper和mybatis-generator是两个东西各自功能不同,结合使用而已
通用mapper:
1,省略单表操作的xml
2,不必写实现类(用通用mapper的单表操作方法不用,用xml中sql(mybatis)也不用)
mybaits VS hibernate
mybatis-generator对应hibernate反向工程
通用mapper对应spring-data-jpa
(一)、通用mapper生成sql过程:
生成具体生成sql的地方在相应的操作方法接口中
public interface SelectOneMapper<T> {
/**
* 鏍规嵁瀹炰綋涓殑灞炴�杩涜鏌ヨ锛屽彧鑳芥湁涓�釜杩斿洖鍊硷紝鏈夊涓粨鏋滄槸鎶涘嚭寮傚父锛屾煡璇㈡潯浠朵娇鐢ㄧ瓑鍙�
*
* @param record
* @return
*/
@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")
T selectOne(T record);
}
public class BaseSelectProvider extends MapperTemplate
“V”型调试
MapperTemplate中setSqlSource:
SqlNode sqlNode = (SqlNode) method.invoke(this, ms);BaseSelectProvider--》dynamicSQL///调用对应操作接口的方法获取对应单表语句
DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode);
setSqlSource(ms, dynamicSqlSource);////自动生成mybatis能用的写在xml中的节点格式语句
MappedStatement ms这个含有mybatis的1,通用配置,2,基于哪个是实体的单表操作,3,参数,4,哪种操作,5,用什么打印日志
sqlNode包含三个段1,select from端,2,表名端,3,where端(由ms得来)
/**
* 重新设置SqlSource
*
* @param ms
* @throws java.lang.reflect.InvocationTargetException
* @throws IllegalAccessException
*/
public void setSqlSource(MappedStatement ms) throws Exception {
if (this.mapperClass == getMapperClass(ms.getId())) {
throw new RuntimeException("请不要配置或扫描通用Mapper接口类:" + this.mapperClass);
}
Method method = methodMap.get(getMethodName(ms));
try {
//第一种,直接操作ms,不需要返回值
if (method.getReturnType() == Void.TYPE) {
method.invoke(this, ms);
}
//第二种,返回SqlNode
else if (SqlNode.class.isAssignableFrom(method.getReturnType())) {
SqlNode sqlNode = (SqlNode) method.invoke(this, ms);
DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode);
setSqlSource(ms, dynamicSqlSource);
}
//第三种,返回xml形式的sql字符串
else if (String.class.equals(method.getReturnType())) {
String xmlSql = (String) method.invoke(this, ms);
SqlSource sqlSource = createSqlSource(ms, xmlSql);
//替换原有的SqlSource
setSqlSource(ms, sqlSource);
} else {
throw new RuntimeException("自定义Mapper方法返回类型错误,可选的返回类型为void,SqlNode,String三种!");
}
//cache
checkCache(ms);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getTargetException() != null ? e.getTargetException() : e);
}
}
protected void setSqlSource(MappedStatement ms, SqlSource sqlSource)
{
MetaObject msObject = SystemMetaObject.forObject(ms);/////////////////////////可知MetaObject其实就是ms
msObject.setValue("sqlSource", sqlSource);
KeyGenerator keyGenerator = ms.getKeyGenerator();
if ((keyGenerator instanceof Jdbc3KeyGenerator)) {
msObject.setValue("keyGenerator", new MultipleJdbc3KeyGenerator());
}
}
MetaObject:mybatis的类
public void setValue(String name, Object value)
{
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
{
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
{
if ((value == null) && (prop.getChildren() != null)) {
return;
}
metaValue = this.objectWrapper.instantiatePropertyValue(name, prop, this.objectFactory);
}
metaValue.setValue(prop.getChildren(), value);
}
else
{
this.objectWrapper.set(prop, value);
}
}
查看这几个类:
SqlSourceBuilder
UnpooledDataSourceFactory
Jdbc3KeyGenerator
可知:在检查注入主键的的时候就用MetaObject设置了一次默认的sqlsource(MetaObject是单例)
在具体时候某个通用mapper的单表方法时重置下MetaObject的sqlsource,之后执行sql的时候取到的MetaObject的sqlsource就是覆盖后的()
这个sqlsource的格式就是传统的mybaits.xml手动写的sql节点的格式,之后就交给mybatis去解析这种格式(mybatis使用节点语句都是放到MetaObject中后使用)
(二)、mybatis中使用ms大致过程:
SelectKeyGenerator///使用的地方调用Executor对象
CachingExecutor////////////////这里直接用ms去执行sql
BaseExecutor
MappedStatement
DynamicSqlSource
SqlSourceBuilder
StaticSqlSource
BoundSql
SelectKeyGenerator:
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter)
{
try
{
if ((parameter != null) && (this.keyStatement != null) && (this.keyStatement.getKeyProperties() != null))
{
String[] keyProperties = this.keyStatement.getKeyProperties();
Configuration configuration = ms.getConfiguration();
MetaObject metaParam = configuration.newMetaObject(parameter);
if (keyProperties != null)
{
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
List<Object> values = keyExecutor.query(this.keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
...
}
}}}
CachingExecutor:
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
DynamicSqlSource:
public BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
StaticSqlSource:
public StaticSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.configuration = configuration;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return new BoundSql(configuration, sql, parameterMappings, parameterObject);
}
参考:
http://blog.csdn.net/isea533/article/details/41892319