Несколько запросов, выполняемых в java в одном операторе


100

Привет, мне было интересно, можно ли выполнить что-то подобное с помощью JDBC, поскольку в настоящее время он предоставляет исключение, хотя это возможно в браузере запросов MySQL.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Хотя я понимаю, что это возможно, если строка запроса SQL будет разделена, а оператор будет выполнен дважды, но мне было интересно, есть ли для этого одноразовый подход.

    String url = "jdbc:mysql://localhost:3306/";
    String dbName = "databaseinjection";
    String driver = "com.mysql.jdbc.Driver";
    String sqlUsername = "root"; 
    String sqlPassword = "abc";

    Class.forName(driver).newInstance();

    connection = DriverManager.getConnection(url+dbName, sqlUsername, sqlPassword);

1
поместить в хранимую процедуру, вызвать хранимую процедуру. означает, что вам также не нужно повторно развертывать код, когда вы хотите внести изменения.
Крис

4
В строке подключения необходимо указать свойство allowMultiQueries=true.
Рахул

вероятный дубликат: как выполнять составные sql-запросы в java? [1] [1]: stackoverflow.com/questions/6773393/…
прайагупд

1
Привет, Рахул, в этом проекте я использую простой старый объект подключения, и знаете ли вы, где мне установить «allowMultiQueries = true». В вопрос добавили код объекта подключения
MilindaD

Ответы:


140

Мне было интересно, можно ли выполнить что-то подобное с помощью JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Да, это возможно. Насколько я знаю, есть два пути. Они есть

  1. Установив свойство подключения к базе данных, чтобы разрешить несколько запросов, разделенных точкой с запятой по умолчанию.
  2. Вызывая хранимую процедуру, которая неявно возвращает курсоры.

Следующие примеры демонстрируют две вышеуказанные возможности.

Пример 1 : (Чтобы разрешить несколько запросов):

При отправке запроса на подключение вам необходимо добавить свойство подключения allowMultiQueries=trueк URL-адресу базы данных. Это дополнительное соединение свойство для тех , если уже существует какой - то, как autoReConnect=trueи т.д .. Приемлемые значения для allowMultiQueriesсобственности true, false, yes, и no. Любое другое значение отклоняется во время выполнения с расширением SQLException.

String dbUrl = "jdbc:mysql:///test?allowMultiQueries=true";  

Если такая инструкция не передана, SQLExceptionвыдается сообщение.

Вы должны использовать execute( String sql )или другие его варианты для получения результатов выполнения запроса.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Для перебора и обработки результатов вам потребуются следующие шаги:

READING_QUERY_RESULTS: // label  
    while ( hasMoreResultSets || stmt.getUpdateCount() != -1 ) {  
        if ( hasMoreResultSets ) {  
            Resultset rs = stmt.getResultSet();
            // handle your rs here
        } // if has rs
        else { // if ddl/dml/...
            int queryResult = stmt.getUpdateCount();  
            if ( queryResult == -1 ) { // no more queries processed  
                break READING_QUERY_RESULTS;  
            } // no more queries processed  
            // handle success, failure, generated keys, etc here
        } // if ddl/dml/...

        // check to continue in the loop  
        hasMoreResultSets = stmt.getMoreResults();  
    } // while results

Пример 2 : Действия, которые необходимо выполнить:

  1. Создайте процедуру с одним или более select, и DMLзапросами.
  2. Вызовите его из java, используя CallableStatement.
  3. Вы можете захватить несколько ResultSets, выполняемых в процедуре.
    Результаты DML не могут быть захвачены, но могут выдать другой результат, select
    чтобы узнать, как повлияли на строки в таблице.

Примерная таблица и процедура :

mysql> create table tbl_mq( i int not null auto_increment, name varchar(10), primary key (i) );
Query OK, 0 rows affected (0.16 sec)

mysql> delimiter //
mysql> create procedure multi_query()
    -> begin
    ->  select count(*) as name_count from tbl_mq;
    ->  insert into tbl_mq( names ) values ( 'ravi' );
    ->  select last_insert_id();
    ->  select * from tbl_mq;
    -> end;
    -> //
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
mysql> call multi_query();
+------------+
| name_count |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

+------------------+
| last_insert_id() |
+------------------+
|                3 |
+------------------+
1 row in set (0.00 sec)

+---+------+
| i | name |
+---+------+
| 1 | ravi |
+---+------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Вызов процедуры из Java :

CallableStatement cstmt = con.prepareCall( "call multi_query()" );  
boolean hasMoreResultSets = cstmt.execute();  
READING_QUERY_RESULTS:  
    while ( hasMoreResultSets ) {  
        Resultset rs = stmt.getResultSet();
        // handle your rs here
    } // while has more rs

К сожалению, это не работает со встроенной версией Derby.
user2428118

@ user2428118: Причина? Наблюдались какие-либо ошибки? Вы проверяли, поддерживает ли драйвер эту функцию?
Рэвиндер Редди

Я добавил allowMultiQueries = true и отлично работает :)
Hazim

Спасибо @RavinderReddy
Siva R

34

Вы можете использовать пакетное обновление, но запросы должны быть запросами действий (например, вставка, обновление и удаление).

Statement s = c.createStatement();
String s1 = "update emp set name='abc' where salary=984";
String s2 = "insert into emp values ('Osama',1420)";  
s.addBatch(s1);
s.addBatch(s2);     
s.executeBatch();

1
Вы не можете использовать этот подход для запросов «call sprocname ('abc', 984)»?
sebnukem

19

Подсказка: если у вас более одного свойства подключения, разделите их:

&

Чтобы дать вам что-то вроде:

url="jdbc:mysql://localhost/glyndwr?autoReconnect=true&allowMultiQueries=true"

Я надеюсь, что это поможет кому-то.

С Уважением,

Глин


11

На основании моего тестирования правильный флаг - «allowMultiQueries = true»


2

Почему бы вам не попробовать написать Stored Procedureдля этого?

Вы можете получить то Result Setже самое Stored Procedureи Insertто, что хотите.

Единственное, что вы можете не получить новые вставленные строки в, Result Setесли вы Insertпосле Select.


1
У вас не всегда есть разрешение на запись хранимой процедуры. Например, это клиентская база данных, из которой вам разрешено только выбирать.
Pedram Bashiri

2

Я думаю, что это самый простой способ множественного выбора / обновления / вставки / удаления. Вы можете запустить столько обновлений / вставок / удалений, сколько захотите после выбора (вы должны сначала сделать выбор (фиктивный, если необходимо)) с executeUpdate (str) (просто используйте новый int (count1, count2, ...)) и если вам нужен новый выбор, закройте «оператор» и «соединение» и создайте новый для следующего выбора. Как пример:

String str1 = "select * from users";
String str9 = "INSERT INTO `port`(device_id, potition, port_type, di_p_pt) VALUE ('"+value1+"', '"+value2+"', '"+value3+"', '"+value4+"')";
String str2 = "Select port_id from port where device_id = '"+value1+"' and potition = '"+value2+"' and port_type = '"+value3+"' ";
try{  
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    theConnection=(Connection) DriverManager.getConnection(dbURL,dbuser,dbpassword);  
    theStatement = theConnection.prepareStatement(str1);
    ResultSet theResult = theStatement.executeQuery();
    int count8 = theStatement.executeUpdate(str9);
    theStatement.close();
    theConnection.close();
    theConnection=DriverManager.getConnection(dbURL,dbuser,dbpassword);
    theStatement = theConnection.prepareStatement(str2);
    theResult = theStatement.executeQuery();

    ArrayList<Port> portList = new ArrayList<Port>();
    while (theResult.next()) {
        Port port = new Port();
        port.setPort_id(theResult.getInt("port_id"));

        portList.add(port);
    }

Я надеюсь, что это помогает


1
Открытие соединения с БД обходится дороже. Не рекомендуется делать это каждый раз. То, что вы указали, должно сделать n попаданий в базу данных для n запросов, что приводит к снижению производительности.
Арун Кумар Мудрабойна
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.