SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; 异常解决
来源:互联网 发布:金庸小说武功排名知乎 编辑:程序博客网 时间:2024/05/22 01:37
在使用Spring+Ibatis集成的时候,使用如下方式配置复杂类型的时候,总是报异常
<result property="orderid" column="OrderId"/>
<result property="customer" column="Customer"/>
<result property="orderLines" select="getOrderLinesByOrder" column="OrderId"/>
</resultMap>
异常如下:
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
<!-- 此处应注入ibatis配置文件,而非sqlMap文件,否则会出现“there is no statement.....异常” -->
<property name="configLocation">
<value>ch10/SpringAndIbatisOneToMany/sqlMapConfig.xml</value>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="testDAO" class="ch10.SpringAndIbatisOneToMany.TestDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="sqlMapClient">
<ref bean="sqlMapClient"/>
</property>
</bean>
源码分析如下:
经代码跟踪发现问题发生在类org.springframework.orm.ibatis.SqlMapClientTemplate中的:
public Object execute(SqlMapClientCallback action) throws DataAccessException {
Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
SqlMapSession session = this.sqlMapClient.openSession();
Connection ibatisCon = null;
try {
if (logger.isDebugEnabled()) {
logger.debug("Opened SqlMapSession [" + this.sqlMapClient + "] for iBATIS operation");
}
Connection springCon = null;
try {
ibatisCon = session.getCurrentConnection();
if (ibatisCon == null) {
springCon = DataSourceUtils.getConnection(getDataSource());
session.setUserConnection(springCon);
if (logger.isDebugEnabled()) {
logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
}
}
return action.doInSqlMapClient(session);
}
catch (SQLException ex) {
throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
}
finally {
DataSourceUtils.releaseConnection(springCon, getDataSource());
}
}
finally {
// Only close SqlMapSession if we know we've actually opened it
// at the present level.
if (ibatisCon == null) {
session.close();
}
}
}
在这段代码里,spring从SqlMapSession得openSession()方法中得到了当前的session, 设定了
它的连接, ibatis就用这个session得到了test与testDetail的内容,但在得到gossip的内容时,
ibatis使用了如下的方法得到session:
类com.ibatis.sqlmap.engine.impl.SqlMapClientImpl中:
public Object queryForObject(String id, Object paramObject) throws SQLException {
return getLocalSqlMapSession().queryForObject(id, paramObject);
}
protected SqlMapSessionImpl getLocalSqlMapSession() {
SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get();
if (sqlMapSession == null || sqlMapSession.isClosed()) {
sqlMapSession = new SqlMapSessionImpl(this);
localSqlMapSession.set(sqlMapSession);
}
return sqlMapSession;
}
在这个方法中可以看出,对于SqlMapClientImpl来说,session应当会被保存在localSqlMapSession中,
在使用时再得到. 问题出现了, spring也是从这个类得到session的, 但在得到session方法:
public SqlMapSession openSession() {
SqlMapSessionImpl sqlMapSession = new SqlMapSessionImpl(this);
sqlMapSession.open();
return sqlMapSession;
}
中, 这个session根本就没有保存进localSqlMapSession, 于是在得到gossip的内容时, 使用的是一个
新的session. 而这个新的session没有调用过setUserConnection, 其对应的transaction也就是初始值null,
而且ibatis在后面的
类com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate中
public Object queryForObject(SessionScope session, String id, Object paramObject, Object resultObject) throws SQLException {
Object object = null;
MappedStatement ms = getMappedStatement(id);
Transaction trans = getTransaction(session);
boolean autoStart = trans == null;
try {
trans = autoStartTransaction(session, autoStart, trans);
RequestScope request = popRequest(session, ms);
try {
object = ms.executeQueryForObject(request, trans, paramObject, resultObject);
} finally {
pushRequest(request);
}
autoCommitTransaction(session, autoStart);
} finally {
autoEndTransaction(session, autoStart);
}
return object;
}
protected Transaction autoStartTransaction(SessionScope session, boolean autoStart, Transaction trans) throws SQLException {
Transaction transaction = trans;
if (autoStart) {
session.getSqlMapTxMgr().startTransaction();
transaction = getTransaction(session);
}
return transaction;
}
根本没有检查transaction是不是null, 于是就有上面的NullPointerException了.
于是将spring方法的代码改为:
public Object execute(SqlMapClientCallback action) throws DataAccessException {
Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
SqlMapSession session = this.sqlMapClient.openSession();
Connection ibatisCon = null;
try {
if (logger.isDebugEnabled()) {
logger.debug("Opened SqlMapSession [" + this.sqlMapClient + "] for iBATIS operation");
}
Connection springCon = null;
try {
ibatisCon = this.sqlMapClient.getCurrentConnection();
if (ibatisCon == null) {
springCon = DataSourceUtils.getConnection(getDataSource());
this.sqlMapClient.setUserConnection(springCon);
if (logger.isDebugEnabled()) {
logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
}
}
return action.doInSqlMapClient(this.sqlMapClient);
}
catch (SQLException ex) {
throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
}
finally {
DataSourceUtils.releaseConnection(springCon, getDataSource());
}
}
finally {
// Only close SqlMapSession if we know we've actually opened it
// at the present level.
if (ibatisCon == null) {
// session.close();
}
}
}
一切就好了.
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属性一定要设置, 这样能保证在一对多时才不会出问题.
- SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; 异常解决
- 异常:SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
- 异常:SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
- SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
- SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null];
- uncategorized SQLException for SQL SQL state [null]; error code [17059] 无法转换为内部表示
- mybatis uncategorized SQLException for SQL []; SQL state [null]; error code [17004]; 无效的列类型
- 1uncategorized SQLException for SQL []; SQL state [99999]; error code [17004]; 无效的列类型: 1111;
- 解决 PreparedStatementCallback; uncategorized SQLException for SQL
- error:for SQL []; SQL state [null]; error code [0]
- SQLException for SQL [n/a]; SQL state [HY000]; error code [1366];
- SQL [ ]; SQL state [null]; error code [17004]; 无效的列类型; nested exception is java.sql.SQLException: 无效
- 报错SQL state [null]; error code [17027]; 流已被关闭; nested exception is java.sql.SQLException: 流已被关闭
- SQL state [null]; error code [17004]; 无效的列类型
- 解决java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket这个异常
- 解决java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket这个异常
- 解决java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket这个异常
- 解决java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Error establishing socket异常
- j2ee 轻量级开发模式
- Linux借机发力 到桌面仍需时日
- 建模的误区—— 走出一般性的设计误区,迈向成功之途
- Cache的几种过期使用样例
- 利用servlet处理XMLHTTP提交的POST数据
- SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; 异常解决
- WEB TEST
- Transact-SQL编程规范
- ActionServlet深入探讨
- 一位软件工程师的6年总结
- js的一些页面处理(iframe的高度可变,回车提交)
- Visual Studio.Net鲜为人知的技巧
- 房子现行记
- css星级效果总结