在JDBC java.sql.Statement类有一个cancel()方法。这可以在另一个线程调用取消当前正在运行的语句。

我怎样才能做到这一点使用Spring?我不能找到一种方法运行查询时得到一个语句引用。我也不能找到一个取消状方法。

下面是一些示例代码。想象这需要长达10秒来执行,并且有时在用户的请求时,我想取消:

    final int i = simpleJdbcTemplate.queryForInt("select max(gameid) from game");

如何将修改这个所以我要一个java.sql.Statement对象的引用?

有帮助吗?

解决方案

让我简化oxbow_lakes的回答:你可以使用查询方法的PreparedStatementCreator变种来访问语句

所以,你的代码:

final int i = simpleJdbcTemplate.queryForInt("select max(gameid) from game");

应该变成:

final PreparedStatement[] stmt = new PreparedStatement[1];
final int i = (Integer)getJdbcTemplate().query(new PreparedStatementCreator() {
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
        stmt[0] = connection.prepareStatement("select max(gameid) from game");
        return stmt[0];
    }
}, new ResultSetExtractor() {
    public Object extractData(ResultSet resultSet) throws SQLException, DataAccessException {
        return resultSet.getString(1);
    }
});

现在取消您只需调用

stmt[0].cancel()

您可能想给一个参考stmt到其他线程实际运行查询之前,或者简单地将其存储为一个成员变量。否则,你无法真正消除东西...

其他提示

您可以通过JdbcTemplate方法,让你可以在PreparedStatementCreator通过执行的东西。你总是可以用它来拦截这引起了Proxy到一个单独的线程发生一些cancel成为cond调用(也许使用一个true)。

public Results respondToUseRequest(Request req) {
    final AtomicBoolean cond = new AtomicBoolean(false);
    requestRegister.put(req, cond);
    return jdbcTemplate.query(new PreparedStatementCreator() {
             public PreparedStatement createPreparedStatement(Connection conn) {
               PreparedStatement stmt = conn.prepareStatement();
               return proxyPreparedStatement(stmt, cond);
             }
         }, 
         new ResultSetExtractor() { ... });
}        

canceller本身能成功完成时被取消;例如

private final static ScheduledExecutorService scheduler =
                 Executors.newSingleThreadedScheduledExecutor();  

PreparedStatement proxyPreparedStatement(final PreparedStatement s, AtomicBoolean cond) {
    //InvocationHandler delegates invocations to the underlying statement
    //but intercepts a query 
    InvocationHandler h = new InvocationHandler() {

        public Object invoke(Object proxy, Method m, Object[] args) {
            if (m.getName().equals("executeQuery") {
                Runnable cancel = new Runnable() {
                    public void run() { 
                        try {
                            synchronized (cond) {
                                while (!cond.get()) cond.wait();
                                s.cancel(); 
                            }
                        } catch (InterruptedException e) { }
                    } 
                }
                Future<?> f = scheduler.submit(cancel);
                try {
                    return m.invoke(s, args);
                } finally {
                    //cancel the canceller upon succesful completion
                    if (!f.isDone()) f.cancel(true); //will cause interrupt
                }
            }
            else {
                return m.invoke(s, args);
            }   
        }

    }

    return (PreparedStatement) Proxy.newProxyInstance(
                getClass().getClassLoader(), 
                new Class[]{PreparedStatement.class}, 
                h);

所以,现在正在响应于用户的解除的代码将如下所示:

cond.set(true);
synchronized (cond) { cond.notifyAll(); }

我的春天假设你的意思是使用JdbcDaoTemplate和/或JdbcTemplate的吗?如果是这样,这并不能真正帮助或阻碍您解决问题。

我会假设你的使用情况是,你执行一个DAO操作在一个线程,而另一个线程进来,要取消第一个线程的操作。

您要解决的是,如何在第二个线程知道要取消哪一个的第一个问题?这是一个固定数量的线程,或几个服务器的GUI?

一旦你已经解决了一部分,你需要弄清楚如何取消声明中的第一个线程。一个简单的方法,这将是存储第一线程的PreparedStatement在外地的地方(也许在一个简单的领域,或许在地图线程ID到报表),允许第二线程进来,检索statwmentand调用取消()在上面。

请记住,这是可能的,取消()可能只是阻止,这取决于您的JDBC驱动程序和数据库。此外,请确保你好好想想同步这里,是你的线程将要进入战斗。

您可以注册在StatementCallback类型JdbcTemplate,将获得与当前活动语句作为参数执行的回调对象。在此回调可以再取消语句:

simpleJdbcTemplate.getJdbcOperations().execute(new StatementCallback() {

    @Override
    public Object doInStatement(final Statement statement) throws SQLException, DataAccessException {
        if (!statement.isClosed()) {
            statement.cancel();
        }

        return null;
    }
});
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top