powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
14 сообщений из 14, страница 1 из 1
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39176831
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если sql-запрос выполняется долго, то иногда хочется его отменить. Но, сюрприз! mysql jdbc коннекор сделан на old сокетах, а они не понимают, если им зовешь Thread.interrupt(). То, что я пока выяснил - это то, что есть метод Statement.cancel(), позволяющий, если драйвер может, отменять выполнение текущего запроса из другого потока. Но как-то это все равно криво. А что делать, если точного объекта Statement нету? Мы ведь можем работать с ORM, кроме того, в другом потоке могут быть сотни разных Statement-ов, какому дергать cancel? Вобщем, Statement есть не всегда.

Мне бы отменить весь поток, например.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
public class QueryTerm {
    static ExecutorService es = Executors.newFixedThreadPool(2);
    static CyclicBarrier barrier = new CyclicBarrier(2);
    
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
//подготовим долгий селект
        es.execute(blockTable);
        barrier.await();
        Future f = es.submit(queryTask);
        Thread.sleep(1000L);
//...
//где-то в программе произошло некоторое внешнее событие и нам надо отменить:
        f.cancel(true); //не срабатывает!
        
    }
    
    static Runnable blockTable = ()->{
            try(Connection conn = DriverManager.getConnection("jdbc:mysql://mysql-host:3306/test?user=root&password=root");
                Statement stmt = conn.createStatement()){
                stmt.execute("CREATE TABLE IF NOT EXISTS `mytable1` (`a` int(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
                stmt.execute("LOCK TABLES mytable1 WRITE");
                stmt.execute("insert ignore into mytable1(a) VALUE("+(int)System.currentTimeMillis()+")");
                barrier.await();
                Thread.sleep(1000000);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        };

            
    static Runnable queryTask = ()->{
            try(Connection conn = DriverManager.getConnection("jdbc:mysql://mysql-host:3306/test?user=root&password=root");
                Statement stmt = conn.createStatement()){
//на этом селекте мы повисаем на долго, и потом мы захотим его прерывать
                try(ResultSet rs = stmt.executeQuery("select * from mytable1");){
                    
                }
            } catch (Exception ex) {
                System.out.println("Terminated! Ура!!! Получилось!!!");
            }
        };
}



У mysql jdbc драйвера есть SocketFactory и у класса Socket есть SocketImplFactory, вот туда бы в одно из мест этих засунуть имплементацию, которая умеет бросать InterrupertException. Но навскидку, таких либ найти не удалось.
Не знаю, может есть еще какой-то способ.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39176837
вадя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39176838
вадя
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39176905
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Придумал.

В драйвере есть параметр socketFactory. У SocketChannel которое из nio есть метод socket(), который возвращает сокет, соответствующий каналу...

Как-то так:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
//добавляем в строку коннекта фабрику
Connection conn = DriverManager.getConnection("jdbc:mysql://mysql-host:3306/test?user=root&password=33600&socketFactory=javaapplication3.FineSocketFactory"
....

public class FineSocketFactory implements com.mysql.jdbc.SocketFactory{ 
    Socket s;
    
    @Override
    public Socket afterHandshake() throws SocketException, IOException {
        return s;
    }

    @Override
    public Socket beforeHandshake() throws SocketException, IOException {
        return s;
    }

    @Override
    public Socket connect(String string, int port, Properties prprts) throws SocketException, IOException {
        SocketAddress sa = new InetSocketAddress(string, port);
        SocketChannel sc = SocketChannel.open(sa);
        sc.configureBlocking(true);
        s = sc.socket();
        return s;
    }
}



Странно, что по умолчанию коннектор пользуется старыми сокетами.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39176958
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вадя http://dev.mysql.com/doc/refman/5.7/en/kill.html
Кстати, Statement.cancel() в JDBC драйвере MySQL именно это и делает.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177087
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мдя, утром оказалось, что вышеприведенного решения недостаточно.

1. Без исплонения Statement.cancel() запрос все равно остается на исполнении в базе, даже если сокет бросает InterruptedException.
2. Если коннекшен достается из пула, то пулу может от такого порвать шаблон. HikariCP ругается.

3. если из сокетового read() было брошено InterruptedException, то не факт, что такой сокет можно дальше использовать. Предположительно, после такого этот сокет использовать нельзя. Вроде, судя по ваершакру, такой сокет финализируется.
По этой причине, исполнение Statement.cancel() в блоке finally или в catch в том же потоке, который надо прервать, не дает эффекта, потому, что сокет которым мы законекчены к базе, уже бросил InterruptedException и не может больше что-то слать. Кроме того, коннекшены, которые бросили InterruptedException должны удаляться из пула - а не факт, что это происходит, хотя hikariCP должен удалять, по идее.
4. особенность работы mysql состоит в том, что если запрос начал выполняться, то коннекшен можно положить, и запрос отменен не будет. Иногда это хорошо, иногда плохо.

То есть Statement.cancel() не "можно", а "всегда нужно" дергать другим потоком. Для этого его туда надо опубликовать, это уже плохо. А иногда все вообще хуже, если у нас например orm, то Statement-а может и не быть...

Ну то есть получается, с отменой запросов/потоков с sql все плохо, архитектура не проработана.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177161
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokТо есть Statement.cancel() не "можно", а "всегда нужно" дергать другим потоком.
Какая связь между потоком и сокетом? Statement.cancel() в MySQL драйвере открывает новое соединение.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177236
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем случае запросы заранее проектируются.
Т.е. отмена запроса из области, когда проектировщику нечем занятся.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177240
Фотография Usman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokВобщем, Statement есть не всегда.Rollback
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177248
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Локшин МаркКакая связь между потоком и сокетом? Statement.cancel() в MySQL драйвере открывает новое соединение.

Ну хз, возможно, Statement.cancel() не может подхватить нужный id, когда соединение уже разорвано. Если подставить драйверу nio-сокет, вызвать InterruptedException и потом из того же потока внутри finally сделать Statement.cancel(), то запрос не отменяется. А если делать из другого потока, то отменяется. Это все, что могу сказать. Как оно там внутри разгребает этот момент я не смотрел.

Поскольку mysql имеет некоторое пороговое значение для кол-ва клиентов, то открывание нового соединения может сработать весьма печально - заблокировать на какое-то время поток, в котором делаешь Statement.cancel()

В tcp протоколе есть такая штука, как urgent data, и в сокетах жавовских она есть, правда, якобы, не везде реализована. Это кадр длиной 1 байт и высокого приоритета. Посылается по соединению, но не становится в конец очереди отправки, а становится в ее начало. При помощи него обрабатываются такие штуки, как CTRL-C. Если бы они сделали отмену через этот механизм, то было б красивее.

Petro123В общем случае запросы заранее проектируются.
Т.е. отмена запроса из области, когда проектировщику нечем занятся.

В большинстве случаев, да. Но драйвер должен покрывать не большинство случаев, а все. Конкретно я хотел сделать отмену запроса при отвале клиента, только у меня не веб, а legacy софтина с хитрым протоколом. И там отвал клиента - это вполне конкретное событие.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177256
Локшин Марк
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokВ tcp протоколе есть такая штука, как urgent data, и в сокетах жавовских она есть, правда, якобы, не везде реализована. Это кадр длиной 1 байт и высокого приоритета. Посылается по соединению, но не становится в конец очереди отправки, а становится в ее начало. При помощи него обрабатываются такие штуки, как CTRL-C. Если бы они сделали отмену через этот механизм, то было б красивее.

И был бы красивый механизм "отстреливания" запросов на MySQL злоумышленником. К тому же никак не решает проблему с уже разорванным соединением.
В PostgeSQL, например, это реализовано более потребно - во время процедуры установления коннекта сервер генерирует 32-битный ключ, посылка которого вместе с кодом команды на порт PostgreSQL (и pid???) отменяет выполняющийся запрос.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39177276
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokВ большинстве случаев, да
OK пришли к одному мнению.
chabapokНо драйвер должен покрывать не большинство случаев, а все
вы драйвер делаете? Драйвер делают для программистов. Согласен, что 0,5 процентов захотт отменять запросы.
chabapokКонкретно я хотел сделать отмену запроса при отвале клиента,
Это вся цель? Сервер сам всё уберёт при "отвале клинета". Он будт в курсе при этом событии.
Т.е. если это драйвер, то удачи!
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39178550
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Локшин МаркchabapokВ tcp протоколе есть такая штука, как urgent data,
И был бы красивый механизм "отстреливания" запросов на MySQL злоумышленником.

Ну это смотря как сделать. :) Конечно можно сделать и злоумышленнико-френдли, но можно и нет.


Petro123Сервер сам всё уберёт при "отвале клинета". Он будт в курсе при этом событии.

Сервер в моем случае представляет из себя велосипед с блэкджеком и шлюпкой :). Но какой-нибудь томкат в силу специфики архитектуры, ничего с базой не сделать не может. Пул может роллбэк сделать, это да - но не более того. Но роллбэк делается уже после того, как все запросы отработали, а речь шла о том, чтобы прибить задачу с несколькими тяжелыми селектами.

Petro123Т.е. если это драйвер, то удачи!
нет, я о том, что в драйвере такая фича могла бы и быть.
...
Рейтинг: 0 / 0
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
    #39178575
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokа речь шла о том, чтобы прибить задачу с несколькими тяжелыми селектами.
тут противоречие.
По практике, такие задачи не делают...или делают, но очень сильно и плотно работая с сервером.
Пул для таких задач тоже не нужен.
Т.е. это не стандартные задачи и не стандартная архитектура = индивидуальный конкретный проект с очень длинными запросами.
chabapokА что делать, если точного объекта Statement нету? Мы ведь можем работать с ORM, кроме того, в другом потоке могут быть сотни разных Statement-ов, какому дергать cancel? Вобщем, Statement есть не всегда.
итого пришли, что нужно не выдумать все случаи, а решать конкретный проект.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]