分类: Java
2009-09-01 11:39:10
在使用Spring+Ibatis集成的时候,使用如下方式配置复杂类型的时候,总是报异常
<resultMap class="order" id="result">
<result property="orderid" column="OrderId"/>
<result property="customer" column="Customer"/>
<result property="orderLines" select="getOrderLinesByOrder" column="OrderId"/>
resultMap>异常如下:
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
--- The error occurred in ch10/SpringAndIbatisOneToMany/Ibatis.xml.
--- The error occurred while applying a result map.
--- Check the result.
--- Check the result mapping for the 'orderLines' property.
--- Cause: java.lang.NullPointerException; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in ch10/SpringAndIbatisOneToMany/Ibatis.xml.
--- The error occurred while applying a result map.
--- Check the result.
--- Check the result mapping for the 'orderLines' property.
--- Cause: java.lang.NullPointerException
Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in ch10/SpringAndIbatisOneToMany/Ibatis.xml.
--- The error occurred while applying a result map.
--- Check the result.
--- Check the result mapping for the 'orderLines' property.
--- Cause: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:188)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:104)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:566)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:541)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:106)
at org.springframework.orm.ibatis.SqlMapClientTemplate$1.doInSqlMapClient(SqlMapClientTemplate.java:243)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:193)
at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:241)
at ch10.SpringAndIbatisOneToMany.TestDAO.getOrderById(TestDAO.java:11)
at ch10.SpringAndIbatisOneToMany.Test.main(Test.java:22)
Caused by: java.lang.NullPointerException
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.endTransaction(SqlMapExecutorDelegate.java:782)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.endTransaction(SqlMapSessionImpl.java:176)
at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.endTransaction(SqlMapClientImpl.java:154)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.autoEndTransaction(SqlMapExecutorDelegate.java:883)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:622)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:589)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:118)
at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClientImpl.java:95)
at com.ibatis.sqlmap.engine.mapping.result.loader.ResultLoader.getResult(ResultLoader.java:72)
at com.ibatis.sqlmap.engine.mapping.result.loader.ResultLoader.loadResult(ResultLoader.java:59)
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getNestedSelectMappingValue(BasicResultMap.java:502)
at com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.getResults(BasicResultMap.java:340)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.java:381)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleMultipleResults(SqlExecutor.java:301)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:190)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:205)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
... 9 more
先说解决方式,主要是在Spring配置文件中,一定要为SqlMapClientFactoryBean配置DataSource属性,不能光为DAO配置dataSoure
|
|
源码分析如下:
经代码跟踪发现问题发生在类org.springframework.orm.ibatis.SqlMapClientTemplate中的:
|
|
|
|
|
|
|
|
|
|
ibatis的openSession在上一版本时,每次打开的都是同一session, 因为它原来的代码在每次打开前会去localSqlMapSession中查找,如果没有才会打开个新的,而且会在返回前放入localSqlMapSession中,这被认为是一个BUG,所以在这个版本上改为返回一个新的session.而在这个session关闭时,才会把这个session返回给sessionPool中.
而在spring中,如楼上我的贴子所说,新打开的session没有进入localSqlMapSession,在打开一对多的表的子表时, 于是从sessionPool中得到一个没有被spring设置过setUserConnection的session,从而Transaction trans = getTransaction(session);这里没有得到缺省的事务,那么 trans = autoStartTransaction(session, autoStart, trans);代码里就会去找这个session的txManager来启动一个事务,但txManager又是null,于是就会发出nullpoint异常了.
这时关键就是session的txManager是什么时候设置的. 我们可以看一下spring的SqlMapClientFactoryBean的代码就会发现,只有设置了它的dataSource属性时,才会去设置session的txManager, 所以这里就可以看出在一对多表时,SqlMapClientFactoryBean的dataSource属性一定要设置, 这样能保证在一对多时才不会出问题.