ibatis原理是怎样的?原理浅析

知道mybatis的人一定都知道ibatis,虽然说现在ibatis都不怎么被使用了,但是这也不能够让我们放弃对于ibatis的了解,下面一起来看看ibatis的原理方面的内容吧!

ibatis是一个基于Java的半自动化的持久框架,下面来看一下ibatis的核心类图。

ibatis的核心类图

SqlMapClient类它是ibatis的门面,通过ibatis完成的持久化操作都是通过调用SqlMapClient类完成的。

SqlMapClient把所有的操作都转给类SqlMapExecutorDelegate类,SqlMapExecutorDelegate类存放解析配置文件生成的类。

例如:

数据源,parameterMap,resultMap, MappedStatement(对增删改查语句的封装)等等,SqlExecutor是最终执行sql语句的地方。

MappedStatement类包含对参数数组进行包装的ParameterMapping[]数组,对执行结果进行包装的ResultMapping[]数组。还有对各种不同的sql的包装类Sql。

例如:

一个插入语句,传进来的是一个对象,ibatis就会依据数的数组包装类ParameterMapping[]将参数赋值。

这里的话,这个赋值是通过DataExchange类完成的。

下面是具体的代码:

public Object[] getProperties(Object object)
{
    int i = 0;
    Object[] values = new Object[propertyNames.length];
    try
    {
        for (i = 0; i < propertyNames.length; i++)
        {
            try
            {
                values[i] = getters[i].invoke(object, NO_ARGUMENTS);
            }
            catch (Throwable t)
            {
                throw ClassInfo.unwrapThrowable(t);
            }
        }
    }
    catch (Throwable t)
    {
        throw new RuntimeException("Error getting property '" + getters[i].getName() + "' of '" + object + "'.  Cause: " + t, t);
    }
    return values;
}

对于一个查询语句,对执行结果的处理是通过对ResultMapping[]进行循环处理的,下面是核心代码:

for (int i = 0; i < getResultMappings()
    .length; i++)
{
    ResultMapping mapping = (ResultMapping) getResultMappings()[i];
    errorContext.setMoreInfo(mapping.getErrorString());
    if (mapping.getStatementName() != null)
    {
        if (resultClass == null)
        {
            throw new SqlMapException("The result class was null when trying to get results for ResultMap named " + getId() + ".");
        }
        else if (Map.class.isAssignableFrom(resultClass))
        {
            Class javaType = mapping.getJavaType();
            if (javaType == null)
            {
                javaType = Object.class;
            }
            columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);
        }
        else if (DomTypeMarker.class.isAssignableFrom(resultClass))
        {
            Class javaType = mapping.getJavaType();
            if (javaType == null)
            {
                javaType = DomTypeMarker.class;
            }
            columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);
        }
        else
        {
            Probe p = ProbeFactory.getProbe(resultClass);
            Class type = p.getPropertyTypeForSetter(resultClass, mapping.getPropertyName());
            columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, type);
        }
        foundData = foundData || columnValues[i] != null;
    }
    else if (mapping.getNestedResultMapName() == null)
    {
        columnValues[i] = getPrimitiveResultMappingValue(rs, mapping);
        if (columnValues[i] == null)
        {
            columnValues[i] = doNullMapping(columnValues[i], mapping);
        }
        else
        {
            foundData = true;
        }
    }
}

在这当中,typetype为参数的java类型,Probe p = ProbeFactory.getProbe(resultClass),Class type = p.getPropertyTypeForSetter(resultClass, mapping.getPropertyName())是通过反射获取java类型的getNestedSelectMappingValue(statementScope, rs, mapping, type)调用了prepareBeanParameterObject(StatementScope statementScope, ResultSet rs, ResultMapping mapping, Class parameterType)方法。

下面是具体的方法:

private Object prepareBeanParameterObject(StatementScope statementScope, ResultSet rs, ResultMapping mapping, Class parameterType)

代码:

throws InstantiationException, IllegalAccessException, SQLException
{
    TypeHandlerFactory typeHandlerFactory = getDelegate()
        .getTypeHandlerFactory();
    Object parameterObject;
    if (parameterType == null)
    {
        parameterObject = new HashMap();
    }
    else
    {
        parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(parameterType);
    }
    String complexName = mapping.getColumnName();
    if (complexName.indexOf('=') > -1 ||
        complexName.indexOf(',') > -1)
    {
        StringTokenizer parser = new StringTokenizer(complexName, "{}=, ", false);
        while (parser.hasMoreTokens())
        {
            String propName = parser.nextToken();
            String colName = parser.nextToken();
            Class propType = PROBE.getPropertyTypeForSetter(parameterObject, propName);
            TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(propType);
            Object propValue = propTypeHandler.getResult(rs, colName);
            PROBE.setObject(parameterObject, propName, propValue);
        }
    }
    else
    {
        // single param  
        TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(parameterType);
        if (propTypeHandler == null)
        {
            propTypeHandler = typeHandlerFactory.getUnkownTypeHandler();
        }
        parameterObject = propTypeHandler.getResult(rs, complexName);
    }
    return parameterObject;

typeHandlerFactory依据参数parameterType的类型决定采用哪个handler处理ResultSet的结果,以

StringTypeHandler为例,其getResult(ResultSet rs, String columnName)方法:

public Object getResult(ResultSet rs, String columnName)
throws SQLException
{
    Object s = rs.getString(columnName);
    if (rs.wasNull())
    {
        return null;
    }
    else
    {
        return s;
    }
}

对于ibatis原理你都了解了吗?你对于ibatis框架还有什么不理解的地方吗?请继续通过java架构师栏目来进行相关知识的了解个学习吧。

推荐阅读:

ibatis动态拼接sql实例分享

mybatis相对于ibatis的优势是什么?

ibatis和mybatis的区别是什么?有什么不同?