Mybatis调用存储过程异常-Non supported SQL92 token at position: 1

最近遇到一个奇怪的异常,使用Mybatis调用一个oracle的package时出现一个异常:

Mybatis中xxDAO.xml


异常信息如下:

16:09:32.399 [http-apr-8080-exec-6] ERROR c.xx.xx.xxService - Error occur when getting xx By xx.
org.springframework.jdbc.UncategorizedSQLException: 
### Error querying database.  Cause: java.sql.SQLException: Non supported SQL92 token at position: 1: 
### The error may exist in com/xx/xx/dao/xxDAO.xml
### The error may involve com.xx.xx.dao.xxDAO.getxxByUserId-Inline
### The error occurred while setting parameters
### SQL: {         call ? := XX.do_xxSearch(                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?,                 ?             )         }
### Cause: java.sql.SQLException: Non supported SQL92 token at position: 1: 
; uncategorized SQLException for SQL []; SQL state [99999]; error code [17034]; Non supported SQL92 token at position: 1: ; nested exception is java.sql.SQLException: Non supported SQL92 token at position: 1: 
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84) ~[spring-jdbc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.1.4.RELEASE.jar:4.1.4.RELEASE]
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) ~[mybatis-spring-1.2.1.jar:1.2.1]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:368) ~[mybatis-spring-1.2.1.jar:1.2.1]
	at com.sun.proxy.$Proxy478.selectList(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:198) ~[mybatis-spring-1.2.1.jar:1.2.1]
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:114) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:43) ~[mybatis-3.2.3.jar:3.2.3]
	at com.sun.proxy.$Proxy532.getAppWorkQueueByUserId(Unknown Source) ~[na:na]
	....
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_31]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_31]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_31]
	at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_31]
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:205) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.internal.Errors.process(Errors.java:267) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317) [jersey-common-2.22.1.jar:na]
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154) [jersey-server-2.22.1.jar:na]
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471) [jersey-container-servlet-core-2.22.1.jar:na]
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425) [jersey-container-servlet-core-2.22.1.jar:na]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383) [jersey-container-servlet-core-2.22.1.jar:na]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336) [jersey-container-servlet-core-2.22.1.jar:na]
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223) [jersey-container-servlet-core-2.22.1.jar:na]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [catalina.jar:7.0.42]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.42]
	xx
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.42]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.42]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) [catalina.jar:7.0.42]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) [catalina.jar:7.0.42]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [catalina.jar:7.0.42]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) [catalina.jar:7.0.42]
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) [catalina.jar:7.0.42]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [catalina.jar:7.0.42]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.42]
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023) [tomcat-coyote.jar:7.0.42]
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) [tomcat-coyote.jar:7.0.42]
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1852) [tomcat-coyote.jar:7.0.42]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_31]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_31]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_31]
Caused by: java.sql.SQLException: Non supported SQL92 token at position: 1: 
	at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:199) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:263) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:271) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleSql.handleToken(OracleSql.java:1245) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleSql.handleODBC(OracleSql.java:1136) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleSql.parse(OracleSql.java:1053) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleSql.getSql(OracleSql.java:310) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleSql.getSqlBytes(OracleSql.java:604) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:177) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:950) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1222) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3488) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:3857) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1374) ~[ojdbc6.jar:Oracle JDBC Driver version - "11.1.0.7.0-Production"]
	at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) ~[tomcat-dbcp.jar:7.0.42]
	at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) ~[tomcat-dbcp.jar:7.0.42]
	at org.apache.ibatis.executor.statement.CallableStatementHandler.query(CallableStatementHandler.java:63) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:70) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:57) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:259) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:132) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:115) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104) ~[mybatis-3.2.3.jar:3.2.3]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98) ~[mybatis-3.2.3.jar:3.2.3]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_31]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_31]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_31]
	at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_31]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.1.jar:1.2.1]
	... 53 common frames omitted
Feb 21, 2017 4:09:32 PM org.glassfish.jersey.filter.LoggingFilter log

这个异常实际上原因很简单,是因为xxDAO.xml中的大括号换行引起,解决方法也简单,升级oracle驱动,或是去掉换行。

  • 但是这个看似简单的原因,实际调查起来就没那么顺利,有兴趣的同学可以看一下我是怎么定位问题

因为这段代码在其他环境都是运行正常,就只有我电脑会有问题,更奇怪的是在我电脑上通过unit testing调用又是正常,一开始我是怀疑是代码不一致引起:unit testing和我部署到tomcat的代码是不一样的,但是通过我再三确认调查,代码肯定是同一份。

所以猜想是不是Mybatis的问题,由于Mybatis只是对jdbc进行封装,最终的底层还是通过jdbc执行数据库操作,会不会是在调用jdbc时传入的参数由于某种原因不一致导致?

  • Jdbc 调用oracle package的方法如下:
public class ProcedureCallTest {
    public static void main(String args[]) throws Exception {
        DriverManager.registerDriver(new sun.jdbc.odbc.JdbcOdbcDriver());
        Connection conn = DriverManager.getConnection("jdbc:odbc:mydata", "sa", "");
        CallableStatement c = conn.prepareCall("{call getsum(?)}");
        c.setInt(1, 100);
        c.execute();
        conn.close();
    }
}

所以有可能不一致的地方有两个地方,conn.prepareCall参数不一样或是c.setInt设置参数有问题,跟踪Mybatis源码:

  • conn.prepareCall在Mybatis源码中位置是:

org.apache.ibatis.executor.statement.CallableStatementHandler.java

protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getResultSetType() != null) {
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareCall(sql);
    }
  }

c.setInt设置参数是代码是:

public void parameterize(Statement statement) throws SQLException {
    registerOutputParameters((CallableStatement) statement);
    parameterHandler.setParameters((CallableStatement) statement);
  }

会根据参数类型调用不同的xxxhander.java设置参数,比如如果是参数类型是String,则调用org.apache.ibatis.type.StringTypeHandler中的ps.setString(i, parameter);设置

最终分析结果让我很困惑,unit testing和tomcat项目传入的参数值都是一样的,所以问题就不应该是Mybatis,而是更底层,就可能是oracle的jdbc驱动不一样引起,这回找到了问题:

unit testing使用的oracle驱动是通过maven配置的:


    com.oracle
    ojdbc7
    12.1.0.2.0
    provided

scope是provided,所以jar是不会加入部署后的项目中,找了一下项目并没有发现有加入oracle驱动,最后是在tomcat的lib中找到,发现竟然是用ojdbc6,和其他运行环境对比了一下,原来他们都用了ojdbc7,升级一下这个包,异常消失,进一步分析结论如下:

是由于xxDAO.xml中的大括号换行引起(高亮的括号),在ojdbc7是没问题,但是在ojdbc6会引起上述异常,如果把换行去掉,改为:


这样在ojdbc6也正常,所以解决方案有两种:

1. 升级驱动
2. 大括号不要换行

我的博客:http://itart.top/article/8198299e2cd443a29feb23a6d7c92553

你可能感兴趣的:(mybaties)