您的位置:首页 > 数据库

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

2016-10-25 10:17 453 查看
原始需求:
有若干个参数,需要作为ibatis拼装sql的参数传入,但是有个参数的值比较特殊,是若干种枚举值。具体到这个case,就是有有限个namespace。我每次需要通过传入多个namespace来查询DB记录。
准备需要传入sqlmap的参数的示例代码如下:

Java代码


Map<String,Object> ibatisParam = new HashMap<String, Object>( );

ibatisParam.put( "keyA","valueA" );

List<String> list = new ArrayList<String>( );

list.add( "namespace1" );

list.add( "namespace2" );

ibatisParam.put( "namespaces",list );

使用的ibatis的sql语句如下:
Xml代码


<select id="listNodeByCriteria" parameterClass="java.util.Map" resultMap="NodeWithPropertyResult">

select <include refid="NodeColumnsWithId"/> from node

<dynamic prepend=" where ">

<isNotNull property="namespaces">

namespace in

<iterate property="namespaces" open="(" conjunction="," close=")">

#value[]#

</iterate>

</isNotNull>

</dynamic>

order by id

limit #querySize# offset #startRow#

</select>

这里的基本需求是map中如果有namespaces这个key,则他的value一定是个list,并且要以这个list作为查询数据的条件。
开始这么写的,报了如下诡异的错误: Java代码


java.lang.reflect.InvocationTargetException

at java.lang.reflect.Method.invoke(Method.java:597)

at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.access$001(AbstractAnnotationAwareTransactionalTests.java:71)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests$1.run(AbstractAnnotationAwareTransactionalTests.java:175)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTest(AbstractAnnotationAwareTransactionalTests.java:283)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTestTimed(AbstractAnnotationAwareTransactionalTests.java:254)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runBare(AbstractAnnotationAwareTransactionalTests.java:172)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)

at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Caused by: java.lang.reflect.InvocationTargetException

at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runTest(JUnitTestCaseDecorator.java:146)

at junit.framework.TestCase.runTest(TestCase.java)

at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runTest(JUnitTestCaseDecorator.java:146)

at mockit.integration.junit3.internal.JUnitTestCaseDecorator.originalRunBare(JUnitTestCaseDecorator.java:105)

at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runBare(JUnitTestCaseDecorator.java:90)

at junit.framework.TestCase.runBare(TestCase.java)

at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.access$001(AbstractAnnotationAwareTransactionalTests.java:71)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests$1.run(AbstractAnnotationAwareTransactionalTests.java:175)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTest(AbstractAnnotationAwareTransactionalTests.java:283)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runTestTimed(AbstractAnnotationAwareTransactionalTests.java:254)

at org.springframework.test.annotation.AbstractAnnotationAwareTransactionalTests.runBare(AbstractAnnotationAwareTransactionalTests.java:172)

at junit.framework.TestResult$1.protect(TestResult.java:110)

at junit.framework.TestResult.runProtected(TestResult.java:128)

at junit.framework.TestResult.run(TestResult.java:113)

at junit.framework.TestCase.run(TestCase.java:124)

at junit.framework.TestSuite.runTest(TestSuite.java:232)

at junit.framework.TestSuite.run(TestSuite.java:227)

at org.junit.internal.runners.JUnit38Cla***unner.run(JUnit38Cla***unner.java:81)

... 6 more

Caused by: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];

--- The error occurred in META-INF/ibatis/mysql/Node.xml.

--- The error occurred while preparing the mapped statement for execution.

--- Check the Node.listNodeByCriteria.

--- Check the parameter map.

--- 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:

--- The error occurred in META-INF/ibatis/mysql/Node.xml.

--- The error occurred while preparing the mapped statement for execution.

--- Check the Node.listNodeByCriteria.

--- Check the parameter map.

--- Cause: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)

at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)

at org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(SqlMapClientTemplate.java:249)

at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClientTemplate.java:296)

at com.alibaba.genova.dependency.common.dao.impl.NodeDaoImpl.listNodesByCriteria(NodeDaoImpl.java:116)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)

at $Proxy8.listNodesByCriteria(Unknown Source)

at com.alibaba.genova.dependency.common.dao.NodeDAOTest.testListNodeByCriteriaWithNameSpace(NodeDAOTest.java:295)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at junit.framework.TestCase.runTest(TestCase.java:168)

... 31 more

Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:

--- The error occurred in META-INF/ibatis/mysql/Node.xml.

--- The error occurred while preparing the mapped statement for execution.

--- Check the Node.listNodeByCriteria.

--- Check the parameter map.

--- Cause: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""

at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:204)

at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryForList(MappedStatement.java:139)

at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:567)

at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:541)

at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:118)

at org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMapClientTemplate.java:298)

at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)

... 47 more

Caused by: com.ibatis.common.beans.ProbeException: Error getting ordinal list from JavaBean. Cause java.lang.NumberFormatException: For input string: ""

at com.ibatis.common.beans.BaseProbe.getIndexedProperty(BaseProbe.java:86)

at com.ibatis.common.beans.ComplexBeanProbe.getProperty(ComplexBeanProbe.java:297)

at com.ibatis.common.beans.ComplexBeanProbe.getObject(ComplexBeanProbe.java:198)

at com.ibatis.common.beans.GenericProbe.getObject(GenericProbe.java:74)

at com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.getData(ComplexDataExchange.java:65)

at com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap.getParameterObjectValues(ParameterMap.java:133)

at com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.executeQueryWithCallback(MappedStatement.java:181)

... 53 more

Caused by: java.lang.NumberFormatException: For input string: ""

at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)

at java.lang.Integer.parseInt(Integer.java:470)

at java.lang.Integer.parseInt(Integer.java:499)

at com.ibatis.common.beans.BaseProbe.getIndexedProperty(BaseProbe.java:51)

... 59 more

这个错误提示真的好烂。被NumberFormatException搞迷糊了好一阵。后来请教同事,把上面的sqlmap中的语句改成下面这样就Ok了: Xml代码


<select id="listNodeByCriteria" parameterClass="java.util.Map" resultMap="NodeWithPropertyResult">

select <include refid="NodeColumnsWithId"/> from node

<dynamic prepend=" where ">

<isNotNull property="namespaces">

namespace in

<iterate property="namespaces" open="(" conjunction="," close=")">

#namespaces[]#

</iterate>

</isNotNull>

</dynamic>

order by id

limit #querySize# offset #startRow#

</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代码


class NameSpace{

String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

如果上面的sql中的namespace需要从NameSpace中的name属性取出,这种该怎么写呢?这里只列出关键有区别的代码,其他地方省略。。。Xml代码


<!--namespace是DB中的字段名-->

namespace in

<!--namespaces是Java代码中Map里面List对应的Key-->

<iterate property="namespaces" open="(" conjunction="," close=")">

<!--每一个NameSpace实例的name属性通过namespaces[].name获取-->

#namespaces[].name#

</iterate>

这里,回想一下上面列出的简单场景的情况,这种写法也不难理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 记录 如何