`

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

    博客分类:
  • SQL
 
阅读更多

原始需求:

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

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

        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语句如下:

	<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.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.JUnit38ClassRunner.run(JUnit38ClassRunner.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了:

 

	<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的示例代码如下:

    class NameSpace{
        String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

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

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

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

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

分享到:
评论
1 楼 lijunwyf 2014-12-17  
值得收藏,实用

相关推荐

    iBATIS内置别名列表

    通过对iBATIS内置别名列表的学习,我们不仅能够更好地理解iBATIS的工作原理,还能在实际项目中更加高效地使用该框架。此外,掌握这些内置别名也有助于提高配置文件的可读性和可维护性,减少因错误配置导致的问题。...

    Ibatis资料ibatai sql map iBATIS使用$和#的一些理解

    在使用iBATIS(现已被MyBatis取代)进行数据库操作时,我们常常需要传递参数到SQL语句中。在iBATIS中,有两种主要的方式来处理这些参数:使用`$`和`#`。这两种方式在不同的场景下有不同的效果。 首先,让我们来看看...

    iBatis-设置缓存模式-Java源码(下载)

    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"&gt; &lt;sqlMap namespace="Account"&gt; &lt;typeAlias alias="Account" type="Account"/&gt; ...

    ibatis 用HashMap解决resultClass映射

    List&lt;Map, Object&gt;&gt; testList = (List&lt;Map, Object&gt;&gt;) sqlMap.queryForList("getTest", null); Map, String&gt; result = new HashMap(); for (int i = 0; i (); i++) { Map, Object&gt; tmp = testList.get(i); ...

    iBATIS 三个版对比

    - **iBATIS v2** 和 **iBATIS v3**:分别提供了`queryForObject`、`queryForList`、`selectOne`、`selectList`等方法。 执行方法的变化反映了iBATIS在不同版本中对于API设计的改进,使得用户可以更加方便地调用...

    ibatis2小例子(转)

    "iBatis_SqlMap的配置总结.doc" 很显然,这是对iBatis SqlMap配置的详细总结,可能包含了如何配置数据源、事务管理器、SqlSessionFactory、SqlSession的创建和关闭,以及如何在XML映射文件中定义SQL语句、参数映射和...

    ibatis多对多关系(详细)

    iBatis多对多关系详解 iBatis是一种流行的持久层框架,用于简化Java应用程序和关系数据库之间的交互。在本文档中,我们将详细介绍iBatis在处理多对多关系时的配置和实现。 多对多关系 多对多关系是一种常见的关系...

    ibatis开发文档-技术文档

    在Ibatis中,SQL Map的配置文件(sqlmap.xml)是关键。这个文件包含了所有与数据库交互的SQL语句和相关的映射信息。例如,你可以定义select、insert、update和delete语句,为每个语句指定ID,设置参数和结果集映射。...

    ibatis分页功能

    2. **编写SQL语句**:在SQL映射文件中,你需要写一个包含分页参数的SQL查询。例如: ```xml &lt;select id="selectUsersByPage" parameterType="map" resultType="User"&gt; SELECT * FROM user != null and limit != ...

    ibatis2.0+sqlserver2005环境搭建

    在本教程中,我们将详细介绍如何搭建一个基于Ibatis 2.3.4.726版本和SQL Server 2005的开发环境。Ibatis是一个轻量级的持久层框架,它允许开发者将SQL语句与Java代码分离,提高了数据库操作的灵活性。 首先,确保你...

    Ibatis多表查询

    最后,我们需要在主配置文件中引入上面定义的 `book.xml` 文件,并设置数据库连接等参数。 **主配置文件 (`sqlMapConfig.xml`):** ```xml &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE sqlMapConfig PUBLIC ...

    Ibatis培训教程

    在实际应用中,我们还需要在代码中控制事务的开启、提交和回滚。通常我们会使用 SqlSession 的 `beginTransaction()`、`commit()` 和 `rollback()` 方法: ```java SqlSession session = sqlSessionFactory....

    ibatis特殊操作.doc

    - `SqlMapFactoryBean` 是 Spring 中用于读取 iBATIS 配置文件并创建 `SqlMap` 的工具类。 - 通过这个类,可以在 Spring 容器中配置 iBATIS 相关组件。 - **关键属性:** - **`configLocation`**: 指定 iBATIS ...

    ibatis技术总结

    3. **SQL代码分离**:iBatis允许将SQL语句与Java代码完全分离,这不仅提高了代码的可读性和可维护性,还便于SQL语句的复用。 4. **增强项目分工和可移植性**:通过将SQL语句与业务逻辑分离,iBatis有助于提高团队...

    spring+ibatis集成文档

    ### Spring与iBatis集成开发详解 #### 一、引言 在Java企业级应用开发领域,Spring框架因其强大的依赖注入(DI)和面向切面编程(AOP)能力而备受青睐;而iBatis(现称为MyBatis)则以其简洁的SQL映射功能而闻名。...

    iBATIS教程之快速入门浅析

    接着,我们需要编写iBATIS的核心配置文件`sql-map-config.xml`。此文件中定义了事务管理器(Transaction Manager)和数据源(DataSource)。例如,以下配置示例中,事务管理器类型设置为JDBC,数据源类型设置为...

    Ibatis应用事例

    在开始Ibatis的应用之前,我们需要确保Ibatis能够正确地与数据库建立连接。这一步骤主要涉及到两个文件的配置:`SqlMap.properties` 和 `SqlMapConfig.xml`。 ##### 1. SqlMap.properties 文件配置 `SqlMap....

    ibatis学习锦集

    iBatis是一个优秀的开源持久层框架,它允许开发者将SQL语句直接写在配置文件中,解决了Java中的数据访问层(DAL)问题,提高了开发效率。其核心功能包括: 1. **XML配置文件**:用于存放SQL语句、映射结果集、事务...

    ibatis高级特性

    - **N+1 Select 问题**: 在一对多关联的情况下,如果每个用户的地址都需要单独查询,则会导致 N+1 次数据库查询,这可能会导致性能问题。 - **优化方案**: 可以通过批处理查询或者使用缓存机制来优化。 ##### 2. 一...

Global site tag (gtag.js) - Google Analytics