Как я могу отменить продолжительный запрос с помощью Spring и JDBCTemplate?

  1. Темп-таблица: Темп-таблицу легко создавать и создавать резервные копии данных.

    Табличная переменная: Но табличная переменная требует усилий, когда мы обычно создаем обычные таблицы.

  2. Temp table: результат временной таблицы может использоваться несколькими пользователями.

    Табличная переменная: Но табличная переменная может использоваться только текущим пользователем.

  3. Temp table: временная таблица будет сохранена в базе данных tempdb. Это сделает сетевой трафик. Когда у нас есть большие данные во временной таблице, они должны работать по всей базе данных. Проблема с производительностью будет существовать.

    Табличная переменная: но табличная переменная будет хранить в физической памяти некоторые данные, а затем, когда размер увеличится, она будет перемещена в базу данных tempdb.

  4. Temp table: временная таблица может выполнять все операции DDL. Он позволяет создавать индексы, отбрасывать, изменять и т. Д.,

    Табличная переменная: тогда как табличная переменная не позволяет выполнять операции DDL. Но табличная переменная позволяет нам создавать только кластерный индекс.

  5. Temp table: временная таблица может использоваться для текущего сеанса или глобальной. Так что многопользовательский сеанс может использовать результаты в таблице.

    Табличная переменная: но табличная переменная может использоваться вплоть до этой программы. (Хранимая процедура)

  6. Temp table: переменная Temp не может использовать транзакции. Когда мы выполняем операции DML с временной таблицей, это может привести к откату или фиксации транзакций.

    Табличная переменная: Но мы не можем сделать это для табличной переменной.

  7. Temp таблица: функции не могут использовать временную переменную. Более того, мы не можем выполнить операцию DML в функциях.

    Табличная переменная: Но функция позволяет нам использовать табличную переменную. Но используя переменную таблицы, мы можем сделать это.

  8. Temp таблица: хранимая процедура выполнит перекомпиляцию (не может использовать тот же план выполнения), когда мы используем переменную temp для каждого последующего вызова.

    Табличная переменная: в то время как табличная переменная не будет так делать.

13
задан Steve McLeod 29 June 2009 в 11:38
поделиться

4 ответа

Позвольте мне упростить ответ 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 какому-нибудь другому потоку перед фактическим выполнением запроса или просто сохранить его как переменную-член. В противном случае вы действительно ничего не сможете отменить ...

12
ответ дан 2 December 2019 в 00:47
поделиться

Вы можете выполнять что-то с помощью методов JdbcTemplate , которые позволяют вам передавать PreparedStatementCreator . Вы всегда можете использовать это для перехвата вызовов (возможно, с использованием прокси ), из-за которого отмена происходила в отдельном потоке некоторым cond стало истинным .

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() { ... });
}        

Этот отменяющий сам мог быть отменен после успешного завершения; например

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(); }
1
ответ дан 2 December 2019 в 00:47
поделиться

Я полагаю, под Spring вы имеете в виду использование JdbcDaoTemplate и / или JdbcTemplate? Если да, то это на самом деле не помогает и не мешает вам в решении вашей проблемы.

Я предполагаю, что ваш вариант использования заключается в том, что вы выполняете операцию DAO в одном потоке, а другой поток входит и хочет отменить операция первого потока.

Первая проблема, которую вы должны решить, заключается в том, как второй поток узнает, какой из них нужно отменить? Это графический интерфейс с фиксированным количеством потоков или сервер с несколькими?

После того как вы решили эту часть, вам нужно выяснить, как отменить оператор в первом потоке. Одним из простых подходов к этому было бы хранение PreparedStatement первого потока где-нибудь в каком-либо поле (возможно, в простом поле, возможно, в карте идентификатора потока для операторов), позволяя второму потоку войти, получить статус и вызвать для него cancel ().

Имейте в виду, что cancel () может просто блокироваться, в зависимости от вашего драйвера JDBC и базы данных. Кроме того, не забудьте хорошо подумать о синхронизации, ведь ваши потоки будут драться.

0
ответ дан 2 December 2019 в 00:47
поделиться

Вы можете зарегистрировать объект обратного вызова для введите StatementCallback на JdbcTemplate , который будет выполнен с текущим активным оператором в качестве параметра. Затем в этом обратном вызове вы можете отменить оператор:

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

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

        return null;
    }
});
0
ответ дан 2 December 2019 в 00:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: