Frage

Die JDBC java.sql.Statement Klasse hat eine cancel() Methode. Dies kann in einem anderen Thread aufgerufen werden, um eine aktuell laufende Anweisung abzubrechen.

Wie kann ich dies mit Spring erreichen? Ich kann nicht einen Weg finden, einen Verweis auf eine Erklärung zu erhalten, wenn eine Abfrage ausgeführt wird. Ich kann auch nicht ein Abbrechen-ähnliches Verfahren finden.

Hier ist ein Beispielcode. Stellen Sie sich vor das dauert bis zu 10 Sekunden auszuführen, und manchmal auf die Anforderung des Benutzers, ich will es abbrechen:

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

Wie würde ich ändere dies, so habe ich einen Verweis auf ein Objekt java.sql.Statement?

War es hilfreich?

Lösung

Lassen Sie mich oxbow_lakes Antwort vereinfachen. Sie PreparedStatementCreator Variante der Abfrage-Methode verwenden, können den Zugriff auf die Erklärung zu gewinnen

So Ihr Code:

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

Sollte verwandeln sich in:

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);
    }
});

Jetzt abbrechen Sie gerade anrufen

stmt[0].cancel()

Sie wollen wahrscheinlich ein Hinweis auf stmt zu einem anderen Thread geben, bevor die Abfrage tatsächlich ausgeführt wird, oder einfach speichern Sie es als eine Membervariable. Sie können aber nicht wirklich etwas aufheben ...

Andere Tipps

Sie können Sachen über JdbcTemplate Methoden ausführen, die Sie erlauben in einem PreparedStatementCreator zu passieren. Man könnte dies immer mit Anrufungen abfangen (vielleicht ein Proxy verwenden), die eine cancel verursacht auf einem separaten Thread geschehen durch einige cond true wurde.

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

Dieses canceller konnte sich nach dem erfolgreichen Abschluss abgebrochen werden; zum Beispiel

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);

So, jetzt der Code, der einen Benutzers Löschung reagiert würde wie folgt aussehen:

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

Ich gehe davon aus von Spring Sie die Verwendung von JdbcDaoTemplate bedeuten und / oder JdbcTemplate? Wenn ja, ist dies nicht wirklich helfen oder behindern Sie Ihr Problem zu lösen.

Ich werde Ihr Anwendungsfall davon ausgehen, dass Sie einen DAO Betriebes in einem Thread sind die Ausführung und ein anderer Thread kommt und wollen den ersten Thread Vorgang abzubrechen.

Das erste Problem, das Sie lösen müssen, ist, wie funktioniert der zweite Thread wissen, was man zu kündigen? Ist das ein GUI mit einer festen Anzahl von Threads oder einem Server mit mehreren?

Wenn Sie diesen Teil gelöst haben, müssen Sie herausfinden, wie die Aussage in dem ersten Thread abzubrechen. Ein einfacher Ansatz dazu wäre der erste Thread PreparedStatement in einem Feld irgendwo zu speichern (vielleicht in einem einfachen Feld, vielleicht in einer Karte von Thread-ID-Anweisungen), so dass der zweite Thread kommen, rufen Sie den statwmentand Anruf abbrechen () auf sich.

Beachten Sie, dass es möglich ist, die cancel () kann nur blockieren, abhängig von Ihren JDBC-Treiber und Datenbank. Also, stellen Sie sicher, dass Sie über die Synchronisierung hart denken hier sind Ihre Fäden in einen Kampf bekommen gehen.

Sie können einen Rückruf Objekt vom Typ StatementCallback auf JdbcTemplate registrieren, die mit der aktuell aktiven Anweisung als Parameter ausgeführt werden erhalten. In diesem Rückruf können Sie dann brechen Sie die Anweisung:

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

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

        return null;
    }
});
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top