JDBC: запросы к базе данных
Запрос к базе данных означает поиск по ее данным. Вы отправляете операторы SQL в базу данных. Для этого сначала нужно открыть соединение с базой данных. Когда у вас есть открытое соединение, вам нужно создать объект Statement, например:
Statement statement = connection.createStatement();
После того, как вы создали Statement, вы можете использовать его для выполнения SQL-запросов, например так:
String sql = "select * from people"; ResultSet result = statement.executeQuery(sql);
Когда вы выполняете SQL-запрос, вы получаете ResultSet. ResultSet содержит результат вашего запроса SQL. Результат возвращается в строках со столбцами данных. Вы перебираете строки ResultSet следующим образом:
Метод ResultSet.next() перемещается к следующей строке в ResultSet, если строк больше нет. Если строк больше, возвращается true. Если строк больше не было, он вернет false.
Вам нужно вызвать next() хотя бы один раз, прежде чем вы сможете прочитать какие-либо данные. Перед первым вызовом next() ResultSet располагается перед первой строкой.
Вы можете получить данные столбца для текущей строки, вызвав некоторые методы getXXX(), где XXX – это примитивный тип данных. Например:
result.getString ("columnName"); result.getLong ("columnName"); result.getInt ("columnName"); result.getDouble ("columnName"); result.getBigDecimal("columnName"); etc.
Имя столбца для получения значения передается в качестве параметра любому из этих вызовов метода getXXX().
Вместо этого вы также можете передать индекс столбца, например так:
result.getString (1); result.getLong (2); result.getInt (3); result.getDouble (4); result.getBigDecimal(5); etc.
Чтобы это работало, вам нужно знать, какой индекс имеет данный столбец в ResultSet. Вы можете получить индекс данного столбца, вызвав метод ResultSet.findColumn(), например:
int columnIndex = result.findColumn("columnName");
При итерации большого количества строк ссылка на столбцы по их индексу может быть быстрее, чем по их имени.
Когда вы закончите итерацию ResultSet, вам нужно закрыть и ResultSet, и объект Statement, который его создал(если вы закончили с ним, то есть). Вы делаете это, вызывая их методы close(), например так:
result.close(); statement.close();
Конечно, вы должны вызывать эти методы внутри блока finally, чтобы убедиться, что они вызываются, даже если во время итерации ResultSet происходит исключение.
Полный пример
Вот полный пример кода запроса:
Statement statement = connection.createStatement(); String sql = "select * from people"; ResultSet result = statement.executeQuery(sql); while(result.next()) < String name = result.getString("name"); long age = result.getLong("age"); System.out.println(name); System.out.println(age); >result.close(); statement.close();
И вот снова пример с добавленными блоками try-finally. Обратите внимание, я пропустил блоки catch, чтобы сделать пример короче.
Statement statement = null; try < statement = connection.createStatement(); ResultSet result = null; try< String sql = "select * from people"; ResultSet result = statement.executeQuery(sql); while(result.next()) < String name = result.getString("name"); long age = result.getLong("age"); System.out.println(name); System.out.println(age); >> finally < if(result != null) result.close(); >> finally
Processing SQL Statements with JDBC
In general, to process any SQL statement with JDBC, you follow these steps:
This page uses the following method, CoffeesTable.viewTable , from the tutorial sample to demonstrate these steps. This method outputs the contents of the table COFFEES . This method will be discussed in more detail later in this tutorial:
public static void viewTable(Connection con) throws SQLException < String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; try (Statement stmt = con.createStatement()) < ResultSet rs = stmt.executeQuery(query); while (rs.next()) < String coffeeName = rs.getString("COF_NAME"); int supplierID = rs.getInt("SUP_ID"); float price = rs.getFloat("PRICE"); int sales = rs.getInt("SALES"); int total = rs.getInt("TOTAL"); System.out.println(coffeeName + ", " + supplierID + ", " + price + ", " + sales + ", " + total); >> catch (SQLException e) < JDBCTutorialUtilities.printSQLException(e); >>
Establishing Connections
First, establish a connection with the data source you want to use. A data source can be a DBMS, a legacy file system, or some other source of data with a corresponding JDBC driver. This connection is represented by a Connection object. See Establishing a Connection for more information.
Creating Statements
A Statement is an interface that represents a SQL statement. You execute Statement objects, and they generate ResultSet objects, which is a table of data representing a database result set. You need a Connection object to create a Statement object.
For example, CoffeesTable.viewTable creates a Statement object with the following code:
There are three different kinds of statements:
- Statement : Used to implement simple SQL statements with no parameters.
- PreparedStatement : (Extends Statement .) Used for precompiling SQL statements that might contain input parameters. See Using Prepared Statements for more information.
- CallableStatement: (Extends PreparedStatement .) Used to execute stored procedures that may contain both input and output parameters. See Stored Procedures for more information.
Executing Queries
To execute a query, call an execute method from Statement such as the following:
- execute : Returns true if the first object that the query returns is a ResultSet object. Use this method if the query could return one or more ResultSet objects. Retrieve the ResultSet objects returned from the query by repeatedly calling Statement.getResultSet .
- executeQuery : Returns one ResultSet object.
- executeUpdate : Returns an integer representing the number of rows affected by the SQL statement. Use this method if you are using INSERT , DELETE , or UPDATE SQL statements.
For example, CoffeesTable.viewTable executed a Statement object with the following code:
ResultSet rs = stmt.executeQuery(query);
Processing ResultSet Objects
You access the data in a ResultSet object through a cursor. Note that this cursor is not a database cursor. This cursor is a pointer that points to one row of data in the ResultSet object. Initially, the cursor is positioned before the first row. You call various methods defined in the ResultSet object to move the cursor.
For example, CoffeesTable.viewTable repeatedly calls the method ResultSet.next to move the cursor forward by one row. Every time it calls next , the method outputs the data in the row where the cursor is currently positioned:
ResultSet rs = stmt.executeQuery(query); while (rs.next()) < String coffeeName = rs.getString("COF_NAME"); int supplierID = rs.getInt("SUP_ID"); float price = rs.getFloat("PRICE"); int sales = rs.getInt("SALES"); int total = rs.getInt("TOTAL"); System.out.println(coffeeName + ", " + supplierID + ", " + price + ", " + sales + ", " + total); >// .
Closing Connections
When you are finished using a Connection , Statement , or ResultSet object, call its close method to immediately release the resources it’s using.
Alternatively, use a try -with-resources statement to automatically close Connection , Statement , and ResultSet objects, regardless of whether an SQLException has been thrown. (JDBC throws an SQLException when it encounters an error during an interaction with a data source. See Handling SQL Exceptions for more information.) An automatic resource statement consists of a try statement and one or more declared resources. For example, the CoffeesTable.viewTable method automatically closes its Statement object, as follows:
public static void viewTable(Connection con) throws SQLException < String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"; try (Statement stmt = con.createStatement()) < ResultSet rs = stmt.executeQuery(query); while (rs.next()) < String coffeeName = rs.getString("COF_NAME"); int supplierID = rs.getInt("SUP_ID"); float price = rs.getFloat("PRICE"); int sales = rs.getInt("SALES"); int total = rs.getInt("TOTAL"); System.out.println(coffeeName + ", " + supplierID + ", " + price + ", " + sales + ", " + total); >> catch (SQLException e) < JDBCTutorialUtilities.printSQLException(e); >>
The following statement is a try -with-resources statement, which declares one resource, stmt , that will be automatically closed when the try block terminates:
try (Statement stmt = con.createStatement()) < // . >
Выполнение запросов
Все SQL-запросы можно условно разделить на две группы:
- Получение данных — к ним относится оператор SELECT .
- Изменение данных — к ним относятся операторы INSERT , UPDATE и DELETE .
Для первой группы используется уже знакомый нам метод интерфейса Statement — executeQuery() . В принципе для начала этого метода вполне достаточно. Он покрывает очень большой процент запросов, которые вам придется использовать на реальной работе.
Позже мы познакомимся с дополнительными возможностями, но на данный момент советую запомнить — если ты хочешь просто получить данные из таблицы, то метод executeQuery() в подавляющем большинстве случаев будет самым правильным выбором.
Для второй группы запросов нужно использовать другой метод интерфейса Statement — executeUpdate() . В отличии от метода executeQuery() , который возвращает ResultSet, этот метод возвращает целое число, которое говорит сколько строк в таблице было изменено при исполнении вашего запроса .
Например, ты можешь оператором DELETE FROM employee удалить все строки (посему будьте очень аккуратны). В этом случае метод executeUpdate() вернет количество удаленных строк. В некоторых ситуациях знание о количестве измененных строк бывает удобным для построения алгоритмов работы с данными.
В принципе с этим вопросов можно закончить — главное мы уже увидели. Для выборки данных — executeQuery() . Для изменения данных — executeUpdate() .
Получим количество пользователей в таблице user с помощью методa executeQuery() :
ResultSet results = statement.executeQuery("SELECT Count(*) FROM user"); results.next(); int count = results.getInt(1);
executeUpdate()
Метод executeUpdate() используется тогда, когда твой запрос что-то меняет в таблице. Это может быть что угодно:
- оператор UPDATE
- оператор INSERT
- оператор DELETE
- оператор CALL PROCEDURE
Этот метод возвращает количество измененный (или удаленных) строк.
Давай напишем запрос, который увеличит зарплату всех наших сотрудников на 1000 рублей.
int rowsCount = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
После того как я выполнил этот код, на своей таблице он вернул число 6. В моей таблице было 6 строк. Значит все строки были изменены.
execute ()
Иногда в твоей жизни могут возникнуть ситуации, когда ты точно не знаешь, какой запрос тебе приходится исполнять — выборка или изменение данных. На этот случай создатели JDBC добавили в него еще один универсальный метод — execute() .
Этот метод можно использовать вместо executeQuery() и executeUpdate() методов. А помнишь, чем эти методы отличались? Правильно. Типом результата. Поэтому создатели JDBC придумали такое решение.
Метод execute() возвращает boolean. Если это значение равно true , то значит выполнялся запрос на получение данных, и тебе нужно вызвать метод getResultSet() , чтобы получить данные. Пример:
boolean hasResults = statement.execute("SELECT Count(*) FROM user"); if ( hasResults )
Если это значение равно false , то значит выполнялся запрос на изменение данных, и тебе нужно вызвать метод getUpdateCount() , чтобы получить количество измененных строк. Пример:
boolean hasResults = statement.execute("UPDATE employee SET salary = salary+1000"); if ( !hasResults )
Давай напишем метод, который выводит на экран результат запроса:
public void executeAndPrintSQLQuery(String sqlQuery) < boolean hasResults = statement.execute(sqlQuery); if ( hasResults ) < ResultSet results = statement.getResultSet(); System.out.println(“Строки вашего запроса ниже: ”); while (results.next()) < Integer String name = results.getString(2); System.out.println(results.getRow() + ". " + id + "\t"+ name); >> else < int count = statement.getUpdateCount(); System.out.println(“Количество именных строк: ” + count); >>
Вот так метод execute() обычно применяется на практике.