• Ibatis中sqlmap参数map中还需要套list的情况如何写?


    原始需求:

    有若干个参数,需要作为ibatis拼装sql的参数传入,但是有个参数的值比较特殊,是若干种枚举值。具体到这个case,就是有有限个namespace。我每次需要通过传入多个namespace来查询DB记录。

    准备需要传入sqlmap的参数的示例代码如下:

    Java代码  收藏代码
    1. Map<String,Object> ibatisParam = new HashMap<String, Object>( );  
    2.   
    3. ibatisParam.put( "keyA","valueA" );  
    4.   
    5. List<String> list = new ArrayList<String>( );  
    6. list.add( "namespace1" );  
    7. list.add( "namespace2" );  
    8.   
    9. ibatisParam.put( "namespaces",list );  
     

    使用的ibatis的sql语句如下:

    Xml代码  收藏代码
    1. <select id="listNodeByCriteria"  parameterClass="java.util.Map" resultMap="NodeWithPropertyResult">  
    2.         select <include refid="NodeColumnsWithId"/> from node  
    3.         <dynamic prepend=" where ">  
    4.         <isNotNull property="namespaces">  
    5.             namespace in  
    6.             <iterate property="namespaces" open="(" conjunction="," close=")">  
    7.                 #value[]#  
    8.             </iterate>                      
    9.         </isNotNull>  
    10.     </dynamic>  
    11.        order by id   
    12.        limit #querySize# offset #startRow#   
    13. </select>  

     这里的基本需求是map中如果有namespaces这个key,则他的value一定是个list,并且要以这个list作为查询数据的条件。

    开始这么写的,报了如下诡异的错误:

     

    Java代码  收藏代码
    1. java.lang.reflect.InvocationTargetException  
    2.     at java.lang.reflect.Method.invoke(Method.java:597)  
    3.     at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)  
    4.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.access$001(AbstractAnnotationAwareTransactionalTests.java:71)  
    5.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests$1.run(AbstractAnnotationAwareTransactionalTests.java:175)  
    6.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTest(AbstractAnnotationAwareTransactionalTests.java:283)  
    7.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTestTimed(AbstractAnnotationAwareTransactionalTests.java:254)  
    8.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runBare(AbstractAnnotationAwareTransactionalTests.java:172)  
    9.     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)  
    10.     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)  
    11.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)  
    12.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)  
    13.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)  
    14.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)  
    15. Caused by: java.lang.reflect.InvocationTargetException  
    16.     at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)  
    17.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
    18.     at java.lang.reflect.Method.invoke(Method.java:597)  
    19.     at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runTest(JUnitTestCaseDecorator.java:146)  
    20.     at junit.framework.TestCase.runTest(TestCase.java)  
    21.     at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)  
    22.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
    23.     at java.lang.reflect.Method.invoke(Method.java:597)  
    24.     at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runTest(JUnitTestCaseDecorator.java:146)  
    25.     at mockit.integration.junit3.internal.JUnitTestCaseDecorator.originalRunBare(JUnitTestCaseDecorator.java:105)  
    26.     at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runBare(JUnitTestCaseDecorator.java:90)  
    27.     at junit.framework.TestCase.runBare(TestCase.java)  
    28.     at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)  
    29.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.access$001(AbstractAnnotationAwareTransactionalTests.java:71)  
    30.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests$1.run(AbstractAnnotationAwareTransactionalTests.java:175)  
    31.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTest(AbstractAnnotationAwareTransactionalTests.java:283)  
    32.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTestTimed(AbstractAnnotationAwareTransactionalTests.java:254)  
    33.     at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runBare(AbstractAnnotationAwareTransactionalTests.java:172)  
    34.     at junit.framework.TestResult$1.protect(TestResult.java:110)  
    35.     at junit.framework.TestResult.runProtected(TestResult.java:128)  
    36.     at junit.framework.TestResult.run(TestResult.java:113)  
    37.     at junit.framework.TestCase.run(TestCase.java:124)  
    38.     at junit.framework.TestSuite.runTest(TestSuite.java:232)  
    39.     at junit.framework.TestSuite.run(TestSuite.java:227)  
    40.     at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)  
    41.     ... 6 more  
    42. Caused by: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];     
    43. --- The error occurred in META-INF/ibatis/mysql/Node.xml.    
    44. --- The error occurred while preparing the mapped statement for execution.    
    45. --- Check the Node.listNodeByCriteria.    
    46. --- Check the parameter map.    
    47. --- Cause: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:     
    48. --- The error occurred in META-INF/ibatis/mysql/Node.xml.    
    49. --- The error occurred while preparing the mapped statement for execution.    
    50. --- Check the Node.listNodeByCriteria.    
    51. --- Check the parameter map.    
    52. --- Cause: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""  
    53.     at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)  
    54.     at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)  
    55.     at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)  
    56.     at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)  
    57.     at org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(SqlMapClientTemplate.java:249)  
    58.     at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClientTemplate.java:296)  
    59.     at com.alibaba.genova.dependency.common.dao.impl.NodeDaoImpl.listNodesByCriteria(NodeDaoImpl.java:116)  
    60.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    61.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
    62.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
    63.     at java.lang.reflect.Method.invoke(Method.java:597)  
    64.     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)  
    65.     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)  
    66.     at $Proxy8.listNodesByCriteria(Unknown Source)  
    67.     at com.alibaba.genova.dependency.common.dao.NodeDAOTest.testListNodeByCriteriaWithNameSpace(NodeDAOTest.java:295)  
    68.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    69.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
    70.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
    71.     at java.lang.reflect.Method.invoke(Method.java:597)  
    72.     at junit.framework.TestCase.runTest(TestCase.java:168)  
    73.     ... 31 more  
    74. Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:     
    75. --- The error occurred in META-INF/ibatis/mysql/Node.xml.    
    76. --- The error occurred while preparing the mapped statement for execution.    
    77. --- Check the Node.listNodeByCriteria.    
    78. --- Check the parameter map.    
    79. --- Cause: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""  
    80.     at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:204)  
    81.     at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryForList(MappedStatement.java:139)  
    82.     at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:567)  
    83.     at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:541)  
    84.     at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:118)  
    85.     at org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMapClientTemplate.java:298)  
    86.     at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)  
    87.     ... 47 more  
    88. Caused by: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""  
    89.     at com.ibatis.common.beans.BaseProbe.getIndexedProperty(BaseProbe.java:86)  
    90.     at com.ibatis.common.beans.ComplexBeanProbe.getProperty(ComplexBeanProbe.java:297)  
    91.     at com.ibatis.common.beans.ComplexBeanProbe.getObject(ComplexBeanProbe.java:198)  
    92.     at com.ibatis.common.beans.GenericProbe.getObject(GenericProbe.java:74)  
    93.     at com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.getData(ComplexDataExchange.java:65)  
    94.     at com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap.getParameterObjectValues(ParameterMap.java:133)  
    95.     at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:181)  
    96.     ... 53 more  
    97. Caused by: java.lang.NumberFormatException: For input string: ""  
    98.     at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)  
    99.     at java.lang.Integer.parseInt(Integer.java:470)  
    100.     at java.lang.Integer.parseInt(Integer.java:499)  
    101.     at com.ibatis.common.beans.BaseProbe.getIndexedProperty(BaseProbe.java:51)  
    102.     ... 59 more  

     这个错误提示真的好烂。被NumberFormatException搞迷糊了好一阵。

    后来请教同事,把上面的sqlmap中的语句改成下面这样就Ok了:

     

    Xml代码  收藏代码
    1. <select id="listNodeByCriteria"  parameterClass="java.util.Map" resultMap="NodeWithPropertyResult">  
    2.         select <include refid="NodeColumnsWithId"/> from node  
    3.         <dynamic prepend=" where ">  
    4.         <isNotNull property="namespaces">  
    5.             namespace in  
    6.             <iterate property="namespaces" open="(" conjunction="," close=")">  
    7.                 #namespaces[]#  
    8.                     </iterate>                      
    9.         </isNotNull>  
    10.     </dynamic>  
    11.        order by id   
    12.        limit #querySize# offset #startRow#   
    13. </select>  

    注意,这里只有iterate标签内部的value改成了namespaces,其他完全一样。

    原来在这种定位JavaBean(这里是map)内部的list属性的时候,iterate标签内部的变量名就要与标签上的property属性的值保持一致了。 

    问题原因:

    参考上面的准备Map的Java代码,可以看到,namespaces作为Map的一个key,ibatis在解析的时候,也只能根据这个key来找到他需要遍历的list(就是我们put进去的那个跟namespaces对应的value)。所以这里不能使用namespaces以外的字符串来用在iterate标签内部,必须使用namespaces,这个是由Map在put时使用的key的名字决定的。只是上面的写法确实不太常见,看上去感觉有点像namespaces本身像个集合,这点是需要注意的。

    问题升级:

    上面问题中,Map里面namespaces对应的list里面的元素还是简单的String,所以在上面直接遍历里面的内容即可。但是如果这个list的内容不是String,而是一个对象,比如叫NameSpace,即List<String> --> List<NameSpace>,这里NameSpace的示例代码如下:

     

    Java代码  收藏代码
    1. class NameSpace{  
    2.     String name;  
    3.   
    4.     public String getName() {  
    5.         return name;  
    6.     }  
    7.   
    8.     public void setName(String name) {  
    9.         this.name = name;  
    10.     }  
    11. }  

    如果上面的sql中的namespace需要从NameSpace中的name属性取出,这种该怎么写呢?

    这里只列出关键有区别的代码,其他地方省略。。。

    Xml代码  收藏代码
    1. <!--namespace是DB中的字段名-->                
    2. namespace in  
    3. <!--namespaces是Java代码中Map里面List对应的Key-->  
    4. <iterate property="namespaces" open="(" conjunction="," close=")">  
    5. <!--每一个NameSpace实例的name属性通过namespaces[].name获取-->  
    6.     #namespaces[].name#  
    7. </iterate>      

    这里,回想一下上面列出的简单场景的情况,这种写法也不难理解。

     

    参考:http://hittyt.iteye.com/blog/1518665

  • 相关阅读:
    11.7表单事件 定时器
    11.5真11.6 函数调用 数组字符串的定义和方法
    11.2 面向对象 解析
    11.1 js数据类型 作用域 原型链
    10.31js中级作用域链和this
    定时器
    生出对象的方式
    学习this
    字符串
    全局方法
  • 原文地址:https://www.cnblogs.com/tancp/p/3863841.html
Copyright © 2020-2023  润新知