Темп-таблица: Темп-таблицу легко создавать и создавать резервные копии данных.
Табличная переменная: Но табличная переменная требует усилий, когда мы обычно создаем обычные таблицы.
Temp table: результат временной таблицы может использоваться несколькими пользователями.
Табличная переменная: Но табличная переменная может использоваться только текущим пользователем.
Temp table: временная таблица будет сохранена в базе данных tempdb. Это сделает сетевой трафик. Когда у нас есть большие данные во временной таблице, они должны работать по всей базе данных. Проблема с производительностью будет существовать.
Табличная переменная: но табличная переменная будет хранить в физической памяти некоторые данные, а затем, когда размер увеличится, она будет перемещена в базу данных tempdb.
Temp table: временная таблица может выполнять все операции DDL. Он позволяет создавать индексы, отбрасывать, изменять и т. Д.,
Табличная переменная: тогда как табличная переменная не позволяет выполнять операции DDL. Но табличная переменная позволяет нам создавать только кластерный индекс.
Temp table: временная таблица может использоваться для текущего сеанса или глобальной. Так что многопользовательский сеанс может использовать результаты в таблице.
Табличная переменная: но табличная переменная может использоваться вплоть до этой программы. (Хранимая процедура)
Temp table: переменная Temp не может использовать транзакции. Когда мы выполняем операции DML с временной таблицей, это может привести к откату или фиксации транзакций.
Табличная переменная: Но мы не можем сделать это для табличной переменной.
Temp таблица: функции не могут использовать временную переменную. Более того, мы не можем выполнить операцию DML в функциях.
Табличная переменная: Но функция позволяет нам использовать табличную переменную. Но используя переменную таблицы, мы можем сделать это.
Temp таблица: хранимая процедура выполнит перекомпиляцию (не может использовать тот же план выполнения), когда мы используем переменную temp для каждого последующего вызова.
Табличная переменная: в то время как табличная переменная не будет так делать.
Позвольте мне упростить ответ 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
. Вы всегда можете использовать это для перехвата вызовов (возможно, с использованием прокси
), из-за которого отмена
происходила в отдельном потоке некоторым 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(); }
Я полагаю, под Spring вы имеете в виду использование JdbcDaoTemplate и / или JdbcTemplate? Если да, то это на самом деле не помогает и не мешает вам в решении вашей проблемы.
Я предполагаю, что ваш вариант использования заключается в том, что вы выполняете операцию DAO в одном потоке, а другой поток входит и хочет отменить операция первого потока.
Первая проблема, которую вы должны решить, заключается в том, как второй поток узнает, какой из них нужно отменить? Это графический интерфейс с фиксированным количеством потоков или сервер с несколькими?
После того как вы решили эту часть, вам нужно выяснить, как отменить оператор в первом потоке. Одним из простых подходов к этому было бы хранение PreparedStatement первого потока где-нибудь в каком-либо поле (возможно, в простом поле, возможно, в карте идентификатора потока для операторов), позволяя второму потоку войти, получить статус и вызвать для него cancel ().
Имейте в виду, что cancel () может просто блокироваться, в зависимости от вашего драйвера 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;
}
});