Ibatis原理分析

 ibatis是什么?ibatis是一个基于Java的"半自动化"的持久框架,"半自动化"是指ibatis并不会在运行期自动生成sql语句执行,而是具体的sql需要通过配置文件进行编写,并将所需的参数,以及返回的结果字段映射到指定的POJO.

      ibatis的核心类图


Ibatis原理分析_第1张图片

      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) {

Java代码   收藏代码
  1.     int i = 0;  
  2.   Object[] values = new Object[propertyNames.length];  
  3.   try {  
  4.     for (i = 0; i < propertyNames.length; i++) {  
  5.       try {  
  6.         values[i] = getters[i].invoke(object, NO_ARGUMENTS);  
  7.       } catch (Throwable t) {  
  8.         throw ClassInfo.unwrapThrowable(t);  
  9.       }  
  10.     }  
  11.   } catch (Throwable t) {  
  12.     throw new RuntimeException("Error getting property '" + getters[i].getName() + "' of '" + object + "'.  Cause: " + t, t);  
  13.   }  
  14.   return values;  
  15. }  

其中object是传进来的要插入的对象,propertyNames就是ParameterMapping[]的参数数组,getters是object类的所有get方法的Method方法数组

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

 

 

Java代码   收藏代码
  1. for (int i = 0; i < getResultMappings().length; i++) {  
  2.      ResultMapping mapping = (ResultMapping) getResultMappings()[i];  
  3.      errorContext.setMoreInfo(mapping.getErrorString());  
  4.      if (mapping.getStatementName() != null) {  
  5.        if (resultClass == null) {  
  6.          throw new SqlMapException("The result class was null when trying to get results for ResultMap named " + getId() + ".");  
  7.        } else if (Map.class.isAssignableFrom(resultClass)) {  
  8.          Class javaType = mapping.getJavaType();  
  9.          if (javaType == null) {  
  10.            javaType = Object.class;  
  11.          }  
  12.          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);  
  13.        } else if (DomTypeMarker.class.isAssignableFrom(resultClass)) {  
  14.          Class javaType = mapping.getJavaType();  
  15.          if (javaType == null) {  
  16.            javaType = DomTypeMarker.class;  
  17.          }  
  18.          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);  
  19.        } else {  
  20.          Probe p = ProbeFactory.getProbe(resultClass);  
  21.          Class type = p.getPropertyTypeForSetter(resultClass, mapping.getPropertyName());  
  22.          columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, type);  
  23.        }  
  24.        foundData = foundData || columnValues[i] != null;  
  25.      } else if (mapping.getNestedResultMapName() == null) {  
  26.        columnValues[i] = getPrimitiveResultMappingValue(rs, mapping);  
  27.        if (columnValues[i] == null) {  
  28.          columnValues[i] = doNullMapping(columnValues[i], mapping);  
  29.        } else {  
  30.          foundData = true;  
  31.        }  
  32.      }  
  33.    }  

         其中,type为参数的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)

Java代码   收藏代码
  1.   throws InstantiationException, IllegalAccessException, SQLException {  
  2. TypeHandlerFactory typeHandlerFactory = getDelegate().getTypeHandlerFactory();  
  3.   
  4. Object parameterObject;  
  5. if (parameterType == null) {  
  6.   parameterObject = new HashMap();  
  7. else {  
  8.   parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(parameterType);  
  9. }  
  10. String complexName = mapping.getColumnName();  
  11.   
  12. if (complexName.indexOf('=') > -1  
  13.     || complexName.indexOf(',') > -1) {  
  14.   StringTokenizer parser = new StringTokenizer(complexName, "{}=, "false);  
  15.   while (parser.hasMoreTokens()) {  
  16.     String propName = parser.nextToken();  
  17.     String colName = parser.nextToken();  
  18.     Class propType = PROBE.getPropertyTypeForSetter(parameterObject, propName);  
  19.     TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(propType);  
  20.     Object propValue = propTypeHandler.getResult(rs, colName);  
  21.     PROBE.setObject(parameterObject, propName, propValue);  
  22.   }  
  23. else {  
  24.   // single param  
  25.   TypeHandler propTypeHandler = typeHandlerFactory.getTypeHandler(parameterType);  
  26.   if (propTypeHandler == null) {  
  27.     propTypeHandler = typeHandlerFactory.getUnkownTypeHandler();  
  28.   }  
  29.   parameterObject = propTypeHandler.getResult(rs, complexName);  
  30. }  
  31.   
  32. return parameterObject;  

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

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

 

Java代码   收藏代码
  1. public Object getResult(ResultSet rs, String columnName)  
  2.     throws SQLException {  
  3.   Object s = rs.getString(columnName);  
  4.   if (rs.wasNull()) {  
  5.     return null;  
  6.   } else {  
  7.     return s;  
  8.   }  
  9. }  

你可能感兴趣的:(ibatis)