Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Как решают проблему отмены jdbc-запросов (или всего mysql потока)? / 14 сообщений из 14, страница 1 из 1
22.02.2016, 18:17
    #39176831
chabapok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
Если 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
22.02.2016, 18:34
    #39176837
вадя
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
...
Рейтинг: 0 / 0
22.02.2016, 18:35
    #39176838
вадя
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
...
Рейтинг: 0 / 0
22.02.2016, 21:23
    #39176905
chabapok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
Придумал.

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

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
23.02.2016, 17:15
    #39177161
Локшин Марк
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
chabapokТо есть Statement.cancel() не "можно", а "всегда нужно" дергать другим потоком.
Какая связь между потоком и сокетом? Statement.cancel() в MySQL драйвере открывает новое соединение.
...
Рейтинг: 0 / 0
23.02.2016, 21:04
    #39177236
Petro123
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
В общем случае запросы заранее проектируются.
Т.е. отмена запроса из области, когда проектировщику нечем занятся.
...
Рейтинг: 0 / 0
23.02.2016, 21:14
    #39177240
Usman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
chabapokВобщем, Statement есть не всегда.Rollback
...
Рейтинг: 0 / 0
23.02.2016, 21:44
    #39177248
chabapok
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как решают проблему отмены jdbc-запросов (или всего mysql потока)?
Локшин МаркКакая связь между потоком и сокетом? Statement.cancel() в MySQL драйвере открывает новое соединение.

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

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

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

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

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

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

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


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

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

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


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