Утверждения (Statements)
После того, как соединение было установлено, мы можем начинать взаимодействие с базой данных (далее – БД).
Взаимодействовать с БД мы можем с помощью трех интерфейсов, которые имплементируются каждым драйвером:
Statement
Этот интерфейс используется для доступа к БД для общих целей. Он крайне полезен, когда мы используем статические SQL -выражения во время работы программы. Этот интерфейс не принимает никаких параметров.
PreparedStatement
Этот интерфейс используется в случае, когда мы планируем использовать SQL -выражения множество раз. Он принимает параметры во время работы программы.
CallableStatement
Этот интерфейс становится полезным в случае, когда мы хотим получить доступ к различным процедурам БД. Он также может принимать параметры во время работы программы.
Создание экземпляра Statement
Прежде, чем мы сможем использовать экземпляр Statement для выполнения SQL- запросов, нам необходимо его создать. Для этого используется метод Connection.createStatement(). В коде это выглядит таким образом:
try {
statement =connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
} finally {
/*Do some job...*/
}
После этого мы можем использовать наш экземпляр statement для выполнения SQL-запросов.
Для этой цели интерфейс Statement имеет три метода, которые реализуются каждой конкретной реализацией JDBC- драйвера:
boolean execute (String SQL)
Этот метод возвращает логическое значение
true
, если объект ResultSet может быть получен. В противном случае он возвращает
false
. Он используется для выполнения DDL SQL- запросов ил в случаях, когда мы используем динамический SQL.int executeUpdate (String SQL)
Этот метод возвращает количество столбцов в таблице, на которое повлиял наш SQL -запрос. Мы используем этот метод для выполнения SQL -запросов, когда хотим получить количество задействованных столбцов, например, количество данных по определенному запросу.
ResultSet executeQuery (String SQL)
Этот метод возвращает нам экземпляр ResultSet. Мы используем этот метод в случаях, когда мы рассчитываем получить множество объектов в результате выполнения нашего SQL-запроса. Например, при получении списка элементов, которые удовлетворяют определенным условиям.
Закрытие экземпляра Statement
Когда мы закрываем наше соединение (Connection) для сохранения результатов в БД, мы закрываем и экземпляр Statement.
Для этого мы используем метод close().
Рассмотрим, как это выглядит в нашем коде:
Connection connection = null;
Statement statement = null;
Class.forName(JDBC_DRIVER);
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
try {
statement = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (statement != null) {
statement.close();
}
}
Для понимания того, как это работает на практике, рассмотрим пример простого приложения, в котором мы попытаемся получить данные из БД.
Пример:
import java.sql.*;
public class StatementDemo {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";
static final String USER = "ИМЯ_ПОЛЬЗОВАТЕЛЯ";
static final String PASSWORD = "ВАШ_ПАРОЛЬ";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
System.out.println("Registering JDBC driver...");
Class.forName(JDBC_DRIVER);
System.out.println("Connecting to database...");
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
System.out.println("Creating statement...");
statement = connection.createStatement();
String sql = "SELECT * FROM developers";
Boolean isRetrieved = statement.execute(sql);
System.out.println("Is data retrieved: " + isRetrieved);
System.out.println("Displaying retrieved data:");
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String specialty = resultSet.getString("specialty");
int salary = resultSet.getInt("salary");
System.out.println("id: " + id);
System.out.println("Name: " + name);
System.out.println("Specialty: " + specialty);
System.out.println("Salary: " + salary);
System.out.println("\n===================\n");
}
System.out.println("Closing connection and releasing resources...");
try {
resultSet.close();
statement.close();
connection.close();
}finally {
if(statement !=null){
statement.close();
}
if(connection!=null){
connection.close();
}
}
System.out.println("Thank You.");
}
}
В результате работы программы получим следующий результат:
/*Some System Messages*/
Registering JDBC driver...
Connecting to database...
Creating statement...
Is data retrieved: true
Displaying retrieved data:
id: 1
Name: Proselyte
Specialty: Java
Salary: 2000
===================
id: 2
Name: Peter
Specialty: C++
Salary: 3000
===================
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: 2000
===================
Closing connection and releasing resources...
Thank You.
Создание экземпляра PreparedStatement
PreparedStatement наследует интерфейс Statement, что дает нам определенные преимущества перед обычным Statement. В частности, мы получаем большую гибкость при динамической поддержке аргументов.
Вот как выглядит создание экземпляра PreparedStatement на практике:
try {
String SQL = "Update developers SET salary WHERE specialty = ?";
preparedStatement = connection.prepareStatement(SQL);
}catch (SQLException e){
e.printStackTrace();
}finally {
/*do some job...*/
}
Все параметры, которые отмечены символом ? называются маркерами параметра. Это означает, что они должны быть переданы через параметры метода.
Каждый параметр ссылается на свой порядковый номер в сигнатуре метода. Т.е. первый маркер находится на первом месте, второй – на втором и т.д. В отличие от массивов, здесь отсчет идет с 1. Это связано с особенностями реляционной модели, на которой и основана работа реляционных БД.
Для выполнения SQL-запросов используются методы с такими же названиями (execute(), executeQuery, executeUpdate), которые несколько модифицированы.
Закрытие экземпляра PreparedStatement
Когда мы закрываем наше соединение (Connection) для сохранения результатов в БД, мы таким же образом закрываем и экземпляр PreparedStatement.
Для этого мы используем метод close().
Рассмотрим, как это выглядит в нашем коде:
try {
String SQL = "Update developers SET salary WHERE specialty = ?";
preparedStatement = connection.prepareStatement(SQL);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
}
Для понимания того, как это работает на практике, рассмотрим пример простого приложения с использованием PreparedStatement.
Пример:
import java.sql.*;
public class PreparedStatementDemo {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";
static final String USER = "ИМЯ_ПОЛЬЗОВАТЕЛЯ";
static final String PASSWORD = "ВАШ_ПАРОЛЬ";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
System.out.println("Registering JDBC driver...");
Class.forName(JDBC_DRIVER);
System.out.println("Creating connection...");
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
try {
String SQL = "SELECT * FROM developers";
preparedStatement = connection.prepareStatement(SQL);
System.out.println("Initial developers table content:");
ResultSet resultSet = preparedStatement.executeQuery(SQL);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String specialty = resultSet.getString("specialty");
int salary = resultSet.getInt("salary");
System.out.println("id: " + id);
System.out.println("Name: " + name);
System.out.println("Specialty: " + specialty);
System.out.println("Salary: " + salary);
System.out.println("\n============================\n");
}
SQL = "Update developers SET salary=? WHERE specialty=?";
System.out.println("Creating statement...");
System.out.println("Executing SQL query...");
preparedStatement = connection.prepareStatement(SQL);
preparedStatement.setInt(1, 3000);
preparedStatement.setString(2, "java");
System.out.println("Rows impacted: " + preparedStatement.executeUpdate());
System.out.println("Final developers table content:");
SQL = "SELECT * FROM developers";
resultSet = preparedStatement.executeQuery(SQL);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String specialty = resultSet.getString("specialty");
int salary = resultSet.getInt("salary");
System.out.println("id: " + id);
System.out.println("Name: " + name);
System.out.println("Specialty: " + specialty);
System.out.println("Salary: " + salary);
System.out.println("\n============================\n");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
if(connection!=null){
connection.close();
}
}
System.out.println("Thank You.");
}
}
В результате работы программы получим примерно следующий результат:
/*Some System Messages*/
Registering JDBC driver...
Creating connection...
Initial developers table content:
id: 1
Name: Proselyte
Specialty: Java
Salary: 2000
============================
id: 2
Name: Peter
Specialty: C++
Salary: 3000
============================
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: 2000
============================
id: 4
Name: Eugene
Specialty: Java
Salary: 2200
============================
Creating statement...
Executing SQL query...
Rows impacted: 2
Final developers table content:
id: 1
Name: Proselyte
Specialty: Java
Salary: 3000
============================
id: 2
Name: Peter
Specialty: C++
Salary: 3000
============================
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: 2000
============================
id: 4
Name: Eugene
Specialty: Java
Salary: 3000
============================
Thank You.
В этом приложении сначала получаем и выводим в консоль список всех записей из таблицы developer, после чего устанавливаем salary = 3000 для всех разработчиков, у которых specialty = “Java”.
Создание экземпляра CallableStatement
Экземпляр CallableStatement используется для выполнения процедур непосредственно в самой БД.
Рассмотрим пример, в котором нам необходимо выполнить такую процедуру в MySQL:
DELIMITER $$
DROP PROCEDURE IF EXISTS `developers`.`getDeveloperName` $$
CREATE PROCEDURE PROSELYTE_TUTORIALS.`getDeveloperName`
(IN DEVELOPER_ID INT, OUT DEVELOPER_NAME VARCHAR(50))
BEGIN
SELECT first INTO DEVELOPER_NAME
FROM developers
WHERE id = DEVELOPER_ID;
END $$
DELIMITER ;
Существует три типа параметров: IN, OUT, INOUT. PreparedStatement использует только IN, а CallableStatement, в свою очередь, использует все три.
Рассмотрим, что же это за параметры:
IN
Параметр, значение которого известно в момент, когда создается запрос. Мы назначим параметр IN с помощью метода типа
setXXX()
.OUT
Параметр, значение которого возвращается SQL -запросом. Мы получаем значения из OUT с помощью методов типа
getXXX()
.INOUT
Параметр, который использует входные и выходные значения. Назначим параметр с помощью метода типа
setXXX()
, получим значения с помощью метода типа
getXXX().
В коде, создание экземпляра CallableStatement выглядит следующим образом:
try {
String SQL = "{call getDeveloperName (?, ?)}";
callableStatement = connection.prepareCall(SQL);
}finally {
/* do some job */
}
Строка SQL представляет собой процедуру с параметрами.
Схожим с PreparedStatement способом, мы, используя экземпляр CallableStatement, должны установить значения параметров.
Когда мы используем параметры типа OUT и INOUT, нам необходимо задействовать дополнительный метод registerOutParameter(). Этот метод устанавливает тип данных JDBC в тип данных процедуры.
После того, как мы вызвали процедуру, получим значение из параметра OUT с помощью соответствующего метода getXXX(). Этот метод преобразует полученное значение из типа данных SQL в тип данных Java.
Закрытие экземпляра CallableStatement
Когда мы закрываем наше соединение (Connection) для сохранения результатов в БД, то таким же образом мы и закрываем и экземпляр Statement.
Для этого мы используем метод close().
Рассмотрим, как это выглядит в нашем коде:
try {
String SQL = "{call getDeveloperName (?, ?)}";
callableStatement = connection.prepareCall(SQL);
}finally {
if(callableStatement!=null){
callableStatement.close();
}
}
Для понимания того, как это работает на практике, рассмотрим пример простого приложения
Пример:
Создаем процедуру в нашей БД:
DELIMITER $$
DROP PROCEDURE IF EXISTS PROSELYTE_TUTORIALS.`getDeveloperName` $$
CREATE PROCEDURE PROSELYTE_TUTORIALS.`getDeveloperName`
(IN DEVELOPER_ID INT, OUT DEVELOPER_NAME VARCHAR(50))
BEGIN
SELECT name INTO DEVELOPER_NAME
FROM developers
WHERE id = DEVELOPER_ID;
END $$
DELIMITER ;
Класс CallableStatementDemo
import java.sql.*;
public class CallableStatementDemo {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";
static final String USER = "ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ";
static final String PASSWORD = "ВАШ_ПАРОЛЬ";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection connection = null;
CallableStatement callableStatement = null;
System.out.println("Registering JDBC driver...");
Class.forName(JDBC_DRIVER);
System.out.println("Creating connection...");
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
System.out.println("Creating callable statement...");
try {
String SQL = "{call getDeveloperName (?, ?)}";
callableStatement = connection.prepareCall(SQL);
int developerID = 1;
callableStatement.setInt(1, developerID);
callableStatement.registerOutParameter(2, Types.VARCHAR);
System.out.println("Executing procedure...");
callableStatement.execute();
String developerName = callableStatement.getString(2);
System.out.println("Developer INFO");
System.out.println("id: " + developerID);
System.out.println("Name: " + developerName);
} finally {
if (callableStatement != null) {
callableStatement.close();
}
if (connection != null) {
connection.close();
}
}
System.out.println("Thank You.");
}
}
В результате работы программы получим следующий результат:
/*Some System Messages*/
Registering JDBC driver...
Creating connection...
Creating callable statement...
Executing procedure...
Developer INFO
id: 1
Name: Proselyte
Thank You.