Spring JDBC Template 无法执行 FROM 子句中包含嵌套查询的查询

Posted

技术标签:

【中文标题】Spring JDBC Template 无法执行 FROM 子句中包含嵌套查询的查询【英文标题】:Spring JDBC Template can't execute Queries containing nested Query in the FROM clause 【发布时间】:2016-10-04 15:07:03 【问题描述】:

Spring JDBC 模板无法执行 FROM 子句中包含嵌套查询的查询

我正在使用 spring JDBCTemplate 来执行查询。并且代码使用 SqlRowSet,而不是 RowMapper 或 RowExtractor。

现在执行在 FROM 子句中包含嵌套查询的查询时似乎出现了一些问题。当我在 Workbench 或 mysql 控制台中测试查询时,它工作得非常好。

以下是代码

JdbcTemplate jdbcTemplate = new JdbcTemplate(txManager.getDataSource());
try 
    String sqlQuery = "SELECT profile.user_profile_id, profile.user_id, profile.first_name "
                    + "FROM (SELECT user_profile_id, user_id, first_name FROM user_profile WHERE user_id = 1) AS profile";

    // The following line is throwing exception
    SqlRowSet resultSet = jdbcTemplate.queryForRowSet(sqlQuery); 

    if (resultSet.next()) 
          ...... // Put in a POJO 
      
 catch(DataAccessException e) 
     e.printStackTrace();
     // Throw Proper User Defined Exception

但是,如果我将查询更改为以下内容,它就可以正常工作。

String sqlQuery = "SELECT profile.user_profile_id, profile.user_id, profile.first_name "
                 + "FROM user_profile AS profile";

注意:我的数据库名称是 titans 我收到以下异常。它说表 'titans.*' 不存在。在我看来这很荒谬。

org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [SELECT prof.user_profile_id, prof.user_id, prof.first_name, prof.last_name FROM (SELECT inner_prof.user_profile_id, inner_prof.user_id, inner_prof.first_name, inner_prof.last_name FROM titans.user_profile AS inner_prof WHERE user_id = 1) AS prof ]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'titans.*' doesn't exist
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:237)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:407)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:456)
at org.springframework.jdbc.core.JdbcTemplate.queryForRowSet(JdbcTemplate.java:501)
at com.titansinc.user.dsp.impl.UserDSP.getUserProfileByUserID(UserDSP.java:188)
at com.titansinc.user.service.UserService.getUserProfileByUserID(UserService.java:36)
at controllers.com.titans.play.controllers.Application.testReadMethod(Application.java:40)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$6$$anonfun$apply$24.apply(routes_routing.scala:141)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$6$$anonfun$apply$24.apply(routes_routing.scala:141)
at play.core.Router$HandlerInvokerFactory$$anon$4.resultCall(Router.scala:264)
at play.core.Router$HandlerInvokerFactory$JavaActionInvokerFactory$$anon$15$$anon$1.invocation(Router.scala:255)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:55)
at play.GlobalSettings$1.call(GlobalSettings.java:67)
at play.core.j.JavaAction$$anonfun$11.apply(JavaAction.scala:82)
at play.core.j.JavaAction$$anonfun$11.apply(JavaAction.scala:82)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:40)
at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:46)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:32)
at scala.concurrent.impl.Future$.apply(Future.scala:31)
at scala.concurrent.Future$.apply(Future.scala:492)
at play.core.j.JavaAction$class.apply(JavaAction.scala:82)
at play.core.Router$HandlerInvokerFactory$JavaActionInvokerFactory$$anon$15$$anon$1.apply(Router.scala:252)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130)
at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:129)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:128)
at scala.Option.map(Option.scala:145)
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:128)
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:121)
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:483)
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:483)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:519)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:519)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:496)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:496)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
   Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'titans.*' doesn't exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
at com.mysql.jdbc.Util.getInstance(Util.java:360)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:978)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2526)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2484)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1446)
at com.mysql.jdbc.Field.getCollation(Field.java:448)
at com.mysql.jdbc.ResultSetMetaData.isCaseSensitive(ResultSetMetaData.java:549)
at com.sun.rowset.CachedRowSetImpl.initMetaData(CachedRowSetImpl.java:722)
at com.sun.rowset.CachedRowSetImpl.populate(CachedRowSetImpl.java:639)
at org.springframework.jdbc.core.SqlRowSetResultSetExtractor.createSqlRowSet(SqlRowSetResultSetExtractor.java:79)
at org.springframework.jdbc.core.SqlRowSetResultSetExtractor.extractData(SqlRowSetResultSetExtractor.java:62)
at org.springframework.jdbc.core.SqlRowSetResultSetExtractor.extractData(SqlRowSetResultSetExtractor.java:45)
at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:446)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:396)
... 44 more

【问题讨论】:

您之前是否在 sql 控制台中测试过您的整个查询? 是的@johnnynemonic,它在 mysql 控制台和工作台中运行良好。问题似乎出在 JDBCTemplate 上。 MySQLSyntaxErrorException: Table 'titans.*' doesn't exist 检查 jdbc 数据源配置。是否配置为“泰坦”数据库? @Arunkumar jdbc 数据源配置正确。所有其他查询都工作正常。只有这一个导致了问题。 【参考方案1】:

看起来queryForRowSet(sqlQuery) 方法有这个错误。我在 spring JIRA 上报告了这个错误。

另一种方法是使用ResultSetExtractor or RowMapper 来实现db 调用。此实现不会为上述查询抛出任何异常。

....

String sqlQuery = ".....";
Object[] parameters =  .... ;

ITestPOJO resultList = jdbcTemplate.query(sqlQuery, parameters, 
     new ResultSetExtractor<ITestPOJO>() 

        @Override
        public ITestPOJO extractData(ResultSet rs) throws SQLException, DataAccessException 
             // TODO use ResultSet from here 
             // return ITestPOJO object
        
    );         
...

【讨论】:

以上是关于Spring JDBC Template 无法执行 FROM 子句中包含嵌套查询的查询的主要内容,如果未能解决你的问题,请参考以下文章

Spring之JDBC Template

Spring框架JDBC Template使用教程

spring系统学习--4 Spring:JDBC Template

Spring JDBC Template -实验介绍

spring+jdbc+template+transaction实现

一文解析Spring JDBC Template的使用指导