不能将 resultSet.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE) 与 spring jdbc DaoSupport 与 Oracle 一

Posted

技术标签:

【中文标题】不能将 resultSet.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE) 与 spring jdbc DaoSupport 与 Oracle 一起使用【英文标题】:can not use resultSet.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE) with spring jdbc DaoSupport with Oracle 【发布时间】:2011-01-05 08:27:38 【问题描述】:

我想使用可滚动的结果集,所以当我使用两行代码时:

 rs.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE);
rs.absolute(12);

在我的 DAOimpl 中,我遇到了异常,请帮助解决它们,在此先感谢。

 import oracle.jdbc.OracleTypes;
    import org.springframework.jdbc.core.CallableStatementCallback;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    import org.springframework.stereotype.Component;
    @Component
    public class MyDAOimpl extends JdbcDaoSupport implements
            MyDAO 

        public List<User> getList(final String where) throws Exception 

            return (List) getJdbcTemplate().execute(
                    "call PKG_USER.getUser(?,?)",
                    new CallableStatementCallback() 
                        public Object doInCallableStatement(CallableStatement cs)
                                throws SQLException 

                            cs.setString(1, where);
                            cs.registerOutParameter(2, OracleTypes.CURSOR);
                            cs.execute();

                            ResultSet rs = (ResultSet) cs.getObject(6);

                            rs.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE);
                            rs.absolute(12);

                            List<User> list = new ArrayList<User>();

                            while (rs.next()) 

                                User user = new User(
                                        rs.getString(1),
                                        rs.getString(2), 
                                        rs.getString(3));
                                list.add(user);
                            
                            return list;
                        
                    );

        
    

这是个例外

java.sql.SQLException: Invalid argument(s) in call: setFetchDirection
    oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
    oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
    oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:199)
    oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:263)
    oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:271)
    oracle.jdbc.driver.BaseResultSet.setFetchDirection(BaseResultSet.java:128)

/////////////////////////////////////// ////////////////////////////////////////////

我改变如下,我没有得到任何结果,通常,我的程序返回 100 个用户:

return (List) getJdbcTemplate().execute(new CallableStatementCreator() 

            public CallableStatement createCallableStatement(
                    Connection connection) throws SQLException 
                return connection.prepareCall(
                        "call PKG_USER.getUser(?,?)",
                        ResultSet.TYPE_SCROLL_SENSITIVE,
                        ResultSet.TYPE_SCROLL_INSENSITIVE);
            
        , new CallableStatementCallback() 

            public Object doInCallableStatement(CallableStatement cs)
                    throws SQLException, DataAccessException 

                cs.setString(1, where);
                cs.registerOutParameter(2, OracleTypes.CURSOR);
                cs.execute();

                ResultSet rs = (ResultSet) cs.getObject(6);

                //////not run////
                rs.absolute(12);
                ////////////////

                List<User> list = new ArrayList<User>();

                while (rs.next()) 
                   
                    List<User> list = new ArrayList<User>();

                            while (rs.next()) 

                                User user = new User(
                                        rs.getString(1),
                                        rs.getString(2), 
                                        rs.getString(3));
                                list.add(user);
                            
                            return list;
            
        );

【问题讨论】:

【参考方案1】:

从 jdbc 模板获取自定义结果集。 Spring 提供了 PreparedStatementCreatorFactory,您可以从中创建 PreparedStatementCreator。

PreparedStatementCreatorFactory pc = new PreparedStatementCreatorFactory(sqlQuery, , new int[] Types.VARCHAR);//query and params Types
pc.setResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE);//TYPE_SCROLL_INSENSITIVE 
pc.setUpdatableResults(false);//CONCUR_READ_ONLY

jdbcTemplate.query(pc.newPreparedStatementCreator(listOfParams),
                        myResultSetExtractor);//perform query with custom psc, process results at ResultSetExtractor

【讨论】:

【参考方案2】:

首先,ResultSet.TYPE_SCROLL_SENSITIVE 是一个表示结果集类型的常量,对于需要感染方向setFetchDirection,它肯定不是一个有效的参数。引用ResultSet#setFetchDirection(int direction)的javadoc的参数部分:

direction - 一个 int 指定建议的获取方向; ResultSet.FETCH_FORWARDResultSet.FETCH_REVERSEResultSet.FETCH_UNKNOWN 之一

因此出现异常和消息“调用中的参数无效:setFetchDirection”。

顺便说一句,根据Processing a Scrollable Result Set中Oracle的“JDBC Developer's Guide and Reference”(所有版本都可以从http://tahiti.oracle.com/获得):

预设获取方向

JDBC 2.0 标准允许 预先指定方向的能力, 称为获取方向,供使用 在处理结果集时。这 允许 JDBC 驱动程序优化其 加工。以下结果集 方法已指定:

void setFetchDirection(int direction) throws SQLException * int getFetchDirection() throws SQLException

Oracle JDBC 驱动程序仅支持 前向预设值,您 可以通过输入指定 ResultSet.FETCH_FORWARD静态 常数值。

ResultSet.FETCH_REVERSEResultSet.FETCH_UNKNOWN 不是 支持的。试图指定它们 导致 SQL 警告,并且设置 被忽略。

Oracle Database 11g Release 2 JDBC Drivers 的readme 中也提到了这一点(撰写本文时的终极版本):

可滚动的结果集 实现有以下 限制:

ScrollableResultSet 上的 setFetchDirection() 不起作用 任何东西。

但这一切只是一种旁注,使用setFetchDiretion 根本不是获得可滚动结果集的方法。

要使用 Spring 的 JdbcTemplate 创建可滚动的结果集,您实际上应该使用 execute(CallableStatementCreator csc, CallableStatementCallback action) 方法和自定义 CallableStatementCreator 实现。在此实现中,使用方法Connection.prepareCall(String sql, int resultSetType, int resultSetConcurrency) 创建一个CallableStatement,它将生成具有给定类型和并发性的ResultSet 对象。最后,拨打rs.absolute()


更新:connection.prepareCall()调用有问题,第三个参数应该是并发类型(ResultSet.CONCUR_READ_ONLYResultSet.CONCUR_UPDATABLE)。试试这个:

            return connection.prepareCall(
                    "call PKG_USER.getUser(?,?)",
                    ResultSet.TYPE_SCROLL_SENSITIVE,
                    ResultSet.CONCUR_UPDATABLE);

【讨论】:

请再次检查我的帖子,我正在更改我的代码,但它无法正常运行。非常感谢。 在添加 ResultSet.TYPE_SCROLL_SENSITIVE 和 ResultSet.CONCUR_UPDATABLE 以创建 connection.prepareCall() 方法后,使用 resultSet.absolute(16) 时仍然出现错误 ------------ ------------------------ org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; SQL [] 的未分类 SQLException; SQL 状态 [99999];错误代码 [17075];仅转发结果集的无效操作:绝对;嵌套异常是 java.sql.SQLException: Invalid operation for forward only resultset : absolute 您的可调用语句可能无法返回可滚动的结果集:forward only 结果集 的操作无效。确实有一些限制,请参阅download.oracle.com/docs/cd/B12037_01/java.101/b10979/…。检查您是否可以避免这些限制,否则您将无法做您想做的事情。

以上是关于不能将 resultSet.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE) 与 spring jdbc DaoSupport 与 Oracle 一的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能将类定义为受保护的?

为啥我不能将属性转换为嵌套元素?

为啥不能将窗体的大小绑定到 ApplicationSettings?

为啥不能将匿名方法分配给 var?

为啥我不能将字符串添加到结构中?

为啥我不能将常量数组作为参数传递?