Java — PreparedStatement Java


Содержание

EasyJava

Java в примерах для начинающих

JDBC statements

Интерфейс JDBC ориентирован на работу с декларативными текстовыми запросами (проще говоря — с sql запросами). Однако имея уже установленное соединение с базой напрямую отправить запрос нельзя. Вначале необходимо получить из соединения объект запроса и работать уже с ним.

Statement

Объект запроса получается простым обращением к объекту соединения:

У интерфейса Statement есть три главных метода: executeQuery ( ) , executeUpdate ( ) и execute ( ) . Первый метод ориентирован на запросы, возвращающие данные (select запросы) и возвращает объект данных (result set). Второй метод, executeUpdate ( ) , служит для выполнения запросов не возвращающих данных, таких как insert или update. Этот метод возвращает число строк, которые затронул запрос. Последний метод, execute ( ) , подходит для всех типов запросов и своим значением сообщает, вернул запрос данные или нет: true если запрос вернул данные и false если нет. В первом случае у объекта Statement можно запросить полученный ResultSet вызовом метода getResultSet ( ) .

Экземпляр Statement можно использовать несколько раз и, используя один и тот же объект, выполнять несколько запросов. Есть ровно одно условие — так как объект ResultSet жёстко привязан к Statement , его породившему, то любой следующий запрос закрывает ранее созданный ResultSet и, если требуется, создаёт новый ResultSet . Таким образом, если требуется одновременно работать с несколькими ResultSet , необходимо иметь и несколько Statement .

PreparedStatement

Главным недостатком интерфейса Statement я бы назвал необходимость передавать весь запрос целиком в виде строки, с параметрами и данными. Во-первых это приводит к неуклюжим конструкциям вида «INSERT INTO ORDER_ITEMS (CLIENT_ID, ORDER_ID, ITEM_ID) values (1, 1, » + i + «)» . Во-вторых, при формировании такого запроса очень легко ошибиться, особенно если он собирается из несколько строк и длинее моего примера раз в пять. В третьих, это прямой путь к sql инъекции, что в 21м веке право слово смешно.

Для решения этих проблем в JDBC предусмотрен интерфейс PreparedStatement , который расширяет Statement . Создаётся он тоже из объекта соединения, причём при создании сразу требуется передать запрос. Запрос этот может (и скорее всего будет) содержать параметры, которые на момент создания запроса неизвестны и будут установлены позднее.

Использование PreparedStatement позволяет убить сразу небольшую стайку зайцев: запрос один раз компилируется и оптимизируется на стороне базы данных; параметры передаются безопасно и не могут вызвать sql инъекцию; код становится читабельнее и запрос проще переиспользовать:

Руководство по JDBC. Утверждения (Statements).

В прошлом уроке мы изучили что такое соединение и способы его создания.
После того, как соединение было утсановлено, мы можем начинатть взаимодействие с базой данных (далее – БД).
Взаимодействовать с БД мы можем с помощью трёх интерфейсов, которые имплементируются каждым драйвером:

  • Statement
    Этот интерфейс используется для доступа к БД для общих целей. Он крайне полезен, когда мы используем статические SQL – выражения во время работы программы. Этот интерфейс не принимает никаких параметров.
  • PreparedStatement
    Этот интерфейс используется в случае, когда мы планируем использовать SQL – выражения множество раз. Он принимает параметры во время работы программы.
  • CallableStatement
    Этот интерфейс становится полезным вслучае, когда мы хотим получить досутп к различным процедурам БД. Он также может прнимать параметры во время работы программы.

Создание экземпляра Statement

Прежде, чем мы сможем использовать экземпляр Statement для выполнения SQL – запросов, нам необходимо создать такой экземпляр. ДЛя этого используется метод Connection.createStatement(). В коде это выглядит таким образом:

После этго мы можем использовать наш экземпляр 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) для сохранения результатов в БД мы таким же образом закрываем и экpемпляр Statement.

Для этого мы испольузем метод close().

Рассмотрим, как это выглядит в нашем коде:

Для понимания того, как это работает на практике, рассмотрим пример простого приложения, в котором мы попытаемся получить данные из БД.

В результате работы программы мы получим следующий результат:

Создание экземпляра PreparedStatement

PreparedStatement наследует интерфейс Statement, что даёт нам опредёлнные преимущества перед обычным Statement. В частности, мы получаем большую гибкость при динамичской поддержке аргументов.

Вот как выглядит создание экземпляра PreparedStatement на практике:

Все параметры, которые отмечены символом ? называются маркерами параметра. Это означает, что они должны быть переданы через параметры метода.


Каждый параметр ссылается на свой порядковый номер в сигнатуре метода. Т.е. первый маркер находится на первом месте, второй – на втором и т.д. В отличие от массивов, здесь отсчёт идёт с 1. Это связано с особенностями реляционной модели, на которой и основана работа реляционных БД.

Для выполнения SQL – запросов используются методы с такими же названиями (execute(), executeQuery, executeUpdate), которые несколько модифицированы.

Закрытие экземпляра PreparedStatement

Когда мы закрываем наше соединение (Connection) для сохранения результатов в БД мы таким же образом закрываем и экземпляр PreparedStatement.

Для этого мы испольузем метод close().

Рассмотрим, как это выглядит в нашем коде:

Для понимания того, как это работает на практике, рассмотрим пример простого приложения с использованием PreparedStatement.
Пример:

В результате работы программы мы получим, примерно, следующий результат:

В этом приложении мы сначала получаем и выводим в консоль список всех записей из таблицы developer, после чего устанавливаем salary = 3000 для всех разработчиков, у которых specialty = “Java”.

Создание экземпляра CallableStatement

Экземпляр CallableStatement используется для выполнения процедур, непосредоственно в самой БД.

Рассмотрим пример, в котором нам необходимо выполнить такую процедуру в MySQL:

Существует три типа параметров: IN, OUT, INOUT. PreparedStatement использует только IN, а CallableStatement, в свою очередь, использует все три.

Рассмотрим, что же это за параметры:

  • IN
    Параметр, значение которого известно в момент, когда создаётся запрос. Мы назначем параметр IN с помощью метода типа setXXX().
  • OUT
    Параметр, значение которого возвращается SQL – запросом. Мы получаем значения из OUT с помощью методов типа getXXX().
  • INOUT
    Параметр, который использует входные и выходные значения. Мы назначем параметр с помощью метода типа setXXX(), а получаем значения, с помощью метода типа getXXX().

В коде, создание экземпляра CallableStatement выглядит следующим образом:

Строка SQL представляет собой процедуру, с параметрами.

Схожим с PreparedStatement способом, мы, используя экземпляр CallableStatement, должны установить значения параметров.

Когда мы используем параметры типа OUT и INOUT, нам необходимозадействовать дополнительный метод registerOutParameter(). Этот метод устанавливает тип данных JDBC в тип данных процедуры.

После того, как мы вызвали рпоцедуру, мы получаем значение из параметра OUT с помощью соответствующего метода getXXX(). Этот метод преобразует полученное значение из типа дыннх SQL в тип данных Java.

Закрытие экземпляра CallableStatement

Когда мы закрываем наше соединение (Connection) для сохранения результатов в БД мы таким же образом закрываем и экземпляр Statement.

Для этого мы испольузем метод close().

Рассмотрим, как это выглядит в нашем коде:

Для понимания того, как это работает на практике, рассмотрим пример простого приложения
Пример:

Создаём процедуру в нашей БД:

В результате работы программы мы получим следующий результат:

В этом уроке мы изучили утверждения (statements) их виды и рассмотрели примеры приложений с их использованием.

В следующем уроке мы изучим такой элемент, как Result Set.

Java JDBC PreparedStatement Example

By Lokesh Gupta | Filed Under: JDBC


In database management systems, a prepared statement or parameterized statement is a feature used to execute the same or similar database statements repeatedly with high efficiency. Typically used with SQL statements such as queries or updates, the prepared statement takes the form of a template into which certain constant values are substituted during each execution.

How prepared statement works?

Most relational databases handles a JDBC / SQL query in four steps:

  1. Parse the incoming SQL query
  2. Compile the SQL query
  3. Plan/optimize the data acquisition path
  4. Execute the optimized query / acquire and return data

A Statement will always proceed through the four steps above for each SQL query sent to the database. A Prepared Statement pre-executes steps (1) – (3) in the execution process above. Thus, when creating a Prepared Statement some pre-optimization is performed immediately. The effect is to lessen the load on the database engine at execution time.

Цукерберг рекомендует:  Вакансии Азия-Моторс

Advantages of using prepared statement over simple JDBC statement

  • Pre-compilation and DB-side caching of the SQL statement leads to overall faster execution and the ability to reuse the same SQL statement in batches.
  • Automatic prevention of SQL injection attacks by builtin escaping of quotes and other special characters. Note that this requires that you use any of the PreparedStatement setXxx() methods to set the values and not use inline the values in the SQL string by string-concatenating.
  • Apart from above two main usage, prepared statements makes it easy to work with complex objects like BLOBs and CLOBs.

If you have missed, in previous posts, we have learned about types of JDBC drivers and some basic operations like making database connection using JDBC and then how to execute SELECT Query, and then INSET Query example.

Execution of prepared statements requires following steps:

1) Make a database connection
2) Set values and execute prepared statement

Pre-requisites include setting up a database schema and creating a table at least.

Let’s write above steps in code:

1) Make JDBC database connection

Though we have already learned about it in making JDBC connection, lets recap with this simple code snippet.

2) Set values and execute PreparedStatement

This is the main step and core part in the post. It requires creating a Statement object and then using it’s executeQuery() method.

Let’s see the whole code in working.

Complete JDBC PreparedStatement Example

That’s all in this post. Drop me a comment if something needs explanation.

JDBC PreparedStatement – Select list of rows

A JDBC PreparedStatement example to select a list of rows from the database.

P.S Tested with PostgreSQL 11 and Java 8

Download Source Code


References

About the Author

mkyong

Comments

I think, in short example, the below line of code gives error:
ResultSet rs = preparedStatement.executeQuery(selectSQL );
Here we don’t need to pass “selectSQL” as parameter to executeQuery.

This error can be removed in following way:
ResultSet rs = preparedStatement.executeQuery();

Please correct me if I am wrong.

yes… I think you are right. when I used that way, I got the exception java.sql.SQLException: Use of the executeQuery(String) method is not supported on this type of statement. but in the example, coding is right

you’re right, it happened to me this same morning by mistake :P

No m’enterao de ná, pero te tengo como rojo y como tal te trato.
Saludos.

jajaja da gusto tener camaradas como tu de follower! Un saludo!!

Esto es un foro de programación, no un lugar para mostrar > … Read more »

Disculpa bonico pero, eres tú el que postea asuntos no
relacionados con la programación.

Por otro lado se ve de lejos que no conoces a muchos catalanes, ya que das de hecho que todos somos Arturistas, cuándo este señor es un mamarracho capitalista como cualquier otro de los que tenéis del Ebro para abajo.

Y lo del avatar, es el que uso en Disqus. Y como veo que hay gente a quien le escuece la vista tansolo de verlo, pues como que se va a quedar unos añitos ahí puesto :P

Java PreparedStatement IN clause alternatives

If you are using JDBC API to run queries on database, you should know that PreparedStatement is the better choice than Statement. However since JDBC API allows only one literal for one “?” parameter, PreparedStatement doesn’t work for IN clause queries.

PreparedStatement IN clause

So if we need to execute a database query with IN clause, we need to look for some alternative approach. The aim of this post is to analyze different approaches and you can choose the one that suits your requirements.

Let’s look at these approaches one by one. But before that let’s create a utility program for database connection reading configurations from property file.

Make sure you have JDBC jars in the build path of the project.

Now let’s look at the different approaches and their analysis.

Execute Single Queries

This is the simplest approach. We can get the input and execute single PreparedStatement query multiple times. A sample program with this approach will look like below.

The approach is simple but it’s very slow because if there are 100 parameters then it will make 100 database calls. This will result in 100 ResultSet objects that will overload the system and it will also cause performance hit. So this approach is not recommended.

Using Stored Procedure

We can write a stored procedure and send the input data to the stored procedure. Then we can execute queries one by one in the stored procedure and get the results. This approach gives fastest performance but as we all know that Stored Procedures are database specific. So if our application deals with multiple types of databases such as Oracle, MySQL then it will become hard to maintain. We should use this approach only when we are working on single type of database and there is no plan to change the database server. Since writing stored procedure is out of scope of this tutorial, I will not demonstrate how to use it.

Creating PreparedStatement Query dynamically

This approach involves writing logic to create the PreparedStatement query dynamically based on the size of the elements in IN clause. A simple example showing how to use it will look like below code.

Notice that the query is created dynamically and it will run perfectly. There will be only one database call and the performance will be good. However if the size of user input varies a lot, we won’t get the PreparedStatement benefit of caching and reusing the execution plan. If you are not worried about PreparedStatement caching and there are not many queries with IN clause, then it seems to be the way to go.

Using NULL in PreparedStatement Query

If you really want to utilize the PreparedStatement caching feature, then another approach is to use NULL in PreparedStatement parameters. Suppose that the maximum allowed parameters in the query is 10, then we can write our logic like below.


Notice that above program is using same PreparedStatement query for executing IN clause statement and will get the benefit of query caching and executing plan. For simplicity, I am just returning if the number of input parameters is greater than the parameters size in the query but we can easily extend it to execute in batches to allow any number of inputs.

Now let’s write a simple test program to check the output. For my test program, I am using Employee table created in JDBC DataSource example.

Our test program code is;

When we execute it with some test data in Employee table, we get below output.

That’s all for the different options we have to use PreparedStatement for IN clause in queries. You can use any one of these based on your project requirements.

Руководство Java JDBC

View more Tutorials:

1- Database использующийся в данной статье

2- Что такое JDBC?

  1. DriverManager:
    • Это класс, использующийся для управления списком Driver (database drivers).
  2. Driver:
    • Это интерфейс, использующийся для соединения коммуникации с базой данных, управления коммуникации с базой данных. Когда загружается Driver, программисту не нужно конкретно вызывать его.
  3. Connection:
    • Интерфейс со всеми методами связи с базой данных. Он описывает коммуникационный контекст. Вся связь с базой данных осуществляется только через объект соединения (connection).
  4. Statement:
    • Это интерфейс, включающий команду SQL отправленный в базу данных для анализа, обобщения, планирования и выполнения.

    ResultSet :

    • ResultSet представляет набор записей, извлеченных из-за выполнения запроса.

3- На каком принципе подключается Java к базе данных?

Вопрос для нас в том, что такое » ODBC DataSource«?

ODBC — Open Database Connectivity: Это набор открытых библиотек, которые могут подключаться практически ко всем видам различных баз данных, и это бесплатно. Предоставляется Microsoft.

ODBC DataSource: в операционной системе Windows вы можете объявить соединение ODBC с определенным видом BD. В результате у нас есть источник данных (Data Source).

В JDBC API, JDBC-ODBC Bridge (мост) был настроен так, что JDBC может работать с ODBC Data Source.

Собеседование по Java EE — SQL, JDBC (вопросы и ответы)

Вопросы и ответы для собеседования о применении SQL, JDBC в Java разработке.

к списку вопросов раздела JEE

Вопросы

1. ANSI SQL
2. Основные элементы баз данных – таблицы, процедуры, функции, констрейнты и т.д..
3. Как вы понимаете null в базах данных?
4. Агрегатные функции, как они работают с null. Не забудьте о group by и having
5. Каким образом лучше добавлять большое количество записей в таблицу?
6. Что такое первая нормальная форма и процесс нормализации? Какие бывают нормальные формы?
7. В чем смысл индекса СУБД, как они устроены, как хранятся? Как бы вы реализовали тот же функционал?
8. Что такое JDBC API и когда его используют?
9. Что такое JDBC Driver и какие различные типы драйверов JDBC вы знаете?
10. Как JDBC API помогает достичь слабой связи между Java программой и JDBC Drivers API?
11. Что такое JDBC Connection? Покажите шаги для подключения программы к базе данных.
12. Как используется JDBC DriverManager class?
13. Как получить информацию о сервере базы данных из java программы?
14. Что такое JDBC Statement?
15. Какие различия между execute, executeQuery, executeUpdate?
16. Что такое JDBC PreparedStatement?
17. Как установить NULL значения в JDBC PreparedStatement?
18. Как используется метод getGeneratedKeys() в Statement?
19. Какие преимущества в использовании PreparedStatement над Statement?
20. Какие есть ограничения PreparedStatement и как их преодолеть?
21. Что такое JDBC ResultSet?
22. Какие существуют различные типы JDBC ResultSet?
23. Как используются методы setFetchSize() и SetMaxRows() в Statement?
24. Как вызвать Stored Procedures используя JDBC API?
25. Что такое JDBC Batch Processing и каковы его преимущества?
26. Что такое JDBC Transaction Management и зачем он нужен?
27. Как откатить JDBC транзакцию?
28. Что такое JDBC Savepoint и как он используется?
29. Расскажите о JDBC DataSource. Какие преимущества он дает?
30. Как создать JDBC пул соединений используя JDBC DataSource и JNDI в Apache Tomcat Server?

Цукерберг рекомендует:  C++ - SOS!!! Задача на C++

31. Расскажите про Apache DBCP API.
32. Какие вы знаете уровни изоляции соединений в JDBC?
33. Что вы знаете о JDBC RowSet? Какие существуют различные типы RowSet?
34. В чем разница между ResultSet и RowSet?
35. Приведите пример наиболее распространенных исключений в JDBC.
36. Расскажите о типах данных CLOB и BLOB в JDBC.
37. Что вы знаете о «грязном чтении» (dirty read) в JDBC? Какой уровень изоляции предотвращает этот тип чтения?
38. Какие есть две фазы commit?
39. Приведите пример различных типов блокировки в JDBC.
40. Как вы понимаете DDL и DML выражения?
41. Какая разница между java.util.Date и java.sql.Date?
42. Как вставить изображение или необработанные данные в базу данных?
43. Что вы можете рассказать о фантомном чтении? Какой уровень изоляции его предотвращает?
44. Что такое SQL Warning? Как возвратить SQL предупреждения в JDBC программе?
45. Как запустить Oracle Stored Procedure с объектами базы данных IN/OUT?
46. Приведите пример возникновения java.sql.SQLException: No suitable driver found.
47. Best Practices в JDBC.

Ответы


1. ANSI SQL

SQL (structured query language — «язык структурированных запросов») — формальный непроцедурный язык программирования, применяемый для создания, модификации и управления данными в произвольной реляционной базе данных, управляемой соответствующей системой управления базами данных (СУБД). SQL основывается на исчислении кортежей. Стандарт SQL определяется с помощью кода ANSI.
*Вопрос «расскажите о SQL» очень широкий и не вписывается в рамки этой статьи. К прочтению любая инфа из интернета, например:

SQL : ОБЗОР: http://www.sql.ru/docs/sql/u_sql/ch2.shtml
Wiki: https://ru.wikipedia.org/wiki/SQL

2. Основные элементы баз данных – таблицы, процедуры, функции, констрейнты и т.д.

Поле — это минимальный элемент базы данных, содержащий один неделимый квант информации. Каждое поле характеризуется именем и типом хранящихся в нем данных.
Запись — это совокупность нескольких разнородных полей, описывающая некоторую сущность предметной области.
Таблица базы данных — это набор однородных записей.

Хранимая процедура — объект базы данных, представляющий собой набор SQL-инструкций, который компилируется один раз и хранится на сервере. Хранимые процедуры очень похожи на обыкновенные процедуры языков высокого уровня, у них могут быть входные и выходные параметры и локальные переменные, в них могут производиться числовые вычисления и операции над символьными данными, результаты которых могут присваиваться переменным и параметрам. В хранимых процедурах могут выполняться стандартные операции с базами данных (как DDL, так и DML). Кроме того, в хранимых процедурах возможны циклы и ветвления, то есть в них могут использоваться инструкции управления процессом исполнения.

JDBC API в Java — обзор и туториал

На этот раз я хотел бы уделить внимание работе с базами данных с помощью JDBC API.

Спор под названием Hibernate (точнее JPA) против JDBC оставим в стороне. Оба подхода имеют право на существование. Если хотите услышать мое личное мнение по этому поводу, то загляните в конец статьи.

А сейчас давайте рассмотрим следующие вопросы:

DriverManager и JDBC Driver

Во всех примерах подключения к базе данных в Интернете вы обязательно встретите эти строки:

Где driverClass — это строка с полным именем класса JDBC драйвера, например org.h2.Driver для H2 Database или com.mysql.jdbc.Driver для MySql.

Обычно на этом повествование про драйвер и DriverManager заканчивается. Ну а мы копнем чуть глубже.

Все основные сущности в JDBC API, с которыми вам предстоит работать, являются интерфейсами:

  • Connection;
  • Statement;
  • PreparedStatement;
  • CallableStatement;
  • ResultSet;
  • Driver;
  • DatabaseMetaData.

JDBC драйвер конкретной базы данных как раз и предоставляет реализации этих интерфейсов.

DriverManager — это синглтон, который содержит информацию о всех зарегистрированных драйверах. Метод getConnection на основании параметра URL находит java.sql.Driver соответствующей базы данных и вызывает у него метод connect.

Так а зачем же вызов Class.forName()?

Если посмотреть исходный код реализации любого драйвера он будет содержать статический блок инициализации такого вида:

Вызов Class.forName загружает класс и этим гарантирует выполнение статического блока инициализации, а значит и регистрацию драйвера в DriverManager.

Соединение к базе данных

В статье я предлагаю воспользоваться легковесной базой данных, написанной на Java, под названием H2 Database. В данный момент для нас преимущество ее использования состоит в том, что скачав джарку здесь вы получаете сразу и саму базу данных, и драйвер для подключения к ней, что для обучения очень удобно.

Подробнее об H2 я обязательно расскажу в отдельной статье, а пока что создадим соединение к базе данных:

Таким образом, мы получили реализацию интерфейса java.sql.Connection для нашей базы данных.

Полный код всех примеров можно найти в конце статьи.

Используем Statement и ResultSet

На основании соединения можно получить объект java.sql.Statement для выполнения запросов к базе.

В результате выполнения этого фрагмента кода будет создана таблица user с двумя колонками id и name.

Statement можно использовать для выполнения любых запросов, будь то DDL, DML, либо обычные запросы на выборку данных.

Объект ResultSet — это результат выполнения запроса.


Объекты Connection, Statement и ResultSet после использования необходимо закрывать. Поэтому приведенный выше код необходимо обернуть в try-finally и в блоке finally добавить закрытие ресурсов:

Выглядит не очень красиво, не правда ли. Закрытие ResultSet можно убрать, ведь в соответствии с контрактом:

A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.

Но все равно не то.

С приходом Java 1.7 ситуация немного изменилась в лучшую сторону, так как была добавлена конструкция try-with-resources, которая гарантирует что все Closeable ресурсы будут закрыты после выполнения try блока. Наш код превращается в следующий более элегантный фрагмент:

PreparedStatement и пакетное выполнение запросов

Если вам нужно выполнить несколько похожих запросов, то разумным решением будет использование PreparedStatement.

PreparedStatement представляет собой скомпилированную версию SQL-выражения, выполнение которого будет быстрее и эффективнее.

PreparedStatement поддерживает пакетную (batch) отправку SQL запросов, что значительно уменьшает траффик между клиентом и базой данных. Небольшой пример:

Обратите внимание, что проставлять параметры в PreparedStatement необходимо через индексы, к тому же отсчет идет с единицы. Если параметров много и есть вероятность, что они периодически будут добавляться или удаляться, то можно воспользоваться таким вариантом:

Транзакции в JDBC

Тех, кто знакомился с Hibernate минуя JDBC, обычно очень удивляет работа с транзакциями.

По умолчанию каждое SQL-выражение автоматически коммитится при выполнении statement.execute и подобных методов. Для того, чтобы открыть транзакцию сначала необходимо установить флаг autoCommit у соединения в значение false. Ну а дальше нам пригодятся всем знакомые методы commit и rollback.

Использование DatabaseMetaData

С помощью Connection можно получиь очень полезную сущность DatabaseMetaData. Она позволяет получить метаинформацию о схеме базы данных, а именно какие в базе данных есть объекты — таблицы, колонки, индексы, триггеры, процедуры и так далее.

Лично я часто использую DatabaseMetaData для модификации схемы базы данных программным способом, например:

После добавления новой функциональности можно проверить, а не созданы ли уже соответствующие объекты, и в случае необходимости модифицировать схему.

Заключение

Конечно, JDBC API создано далеко не идеальным. Например, SQLException является checked исключением и его повсюду надо тянуть или оборачивать; работа с PreparedStatement достаточно неудобная, как мы уже видели.

Но в подавляющем большинстве случаев я использую именно JDBC для свои приложений, так как JDBC дает максимальную гибкость и эффективность. Возможно с Hibernate вы сэкономите один день, так как вам не придется писать код для создания схемы, а так же запросы для чтения и записи объектов. Но что такое один день по сравнению со временем существования приложения? К тому же практика показывает, что периодически Hibernate преподносит разрабочикам интересные челенджи, решение которых может забрать не только время, но и нервы

Полный исходный код примеров из статьи можно найти здесь SqlExamples.java.

Если вы считаете, что какому-то вопросу я уделил недостаточно внимания, напишите мне — и я обязательно дополню статью.

Получить запрос из java.sql.PreparedStatement

В моем коде я использую java.sql.PreparedStatement .

Затем я выполняю метод setString() для заполнения подстановочных знаков подготовленного оператора.

Есть ли способ получить (и распечатать) окончательный запрос перед вызовом метода executeQuery() и выполнить запрос? Я просто хочу это для целей отладки.

Это нигде не определено в контракте API JDBC, но если вы повезло, драйвер JDBC, о котором идет речь, может вернуть полный SQL, просто позвонив PreparedStatement#toString() . То есть.

По моему опыту, те, которые делают это, являются, по крайней мере, драйверами PostgreSQL 8.x и MySQL 5.x JDBC. В случае, если ваш драйвер JDBC его не поддерживает, лучше всего использовать оболочку оператора, которая регистрирует все методы setXxx() и, наконец, заполняет строку SQL на toString() на основе зарегистрированной информации. Например Log4jdbc или P6Spy.

Цукерберг рекомендует:  12 текстовых редакторов HTML5

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

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

Java — PreparedStatement Java

JDBC, Java DataBase Connectivity (соединение с базами данных на Java) — промышленный стандарт взаимодействия Java-приложений с различными СУБД. Реализован в виде пакета java.sql , входящего в состав Java SE.


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

В чем заключаются преимущества использования JDBC?

Преимуществами JDBC считают:

  • Лёгкость разработки: разработчик может не знать специфики базы данных, с которой работает;
  • Код практически не меняется, если компания переходит на другую базу данных (количество изменений зависит исключительно от различий между диалектами SQL);
  • Не нужно дополнительно устанавливать клиентскую программу;
  • К любой базе данных можно подсоединиться через легко описываемый URL.

Что из себя представляет JDBC URL?

JDBC URL состоит из:

: (протокола) — всегда jdbc: .

  • : (подпротокола) — это имя драйвера или имя механизма соединения с базой данных. Подпротокол может поддерживаться одним или несколькими драйверами. Лежащий на поверхности пример подпротокола — это «odbc», отведенный для URL, обозначающих имя источника данных ODBC. В случае необходимости использовать сервис имен (т.е. имя базы данных в JDBC URL не будет действительным именем базы данных), то подпротоколом может выступать сервис имен.
  • (подимени) — это идентификатор базы данных. Значение подимени может менятся в зависимости от подпротокола, и может также иметь под-подимя с синтаксисом, определяемым разработчиком драйвера. Назначение подимени — это предоставление всей информации, необходимой для поиска базы данных. Например, если база данных находится в Интернет, то в состав подимени JDBC URL должен быть включен сетевой адрес, подчиняющийся следующим соглашениям: // :

    Пример JDBC URL для подключения к MySQL базе данных «Test» расположенной по адресу localhost и ожидающей соединений по порту 3306: jdbc:mysql://localhost:3306/Test

    Из каких частей стоит JDBC?

    JDBC состоит из двух частей:

    • JDBC API, который содержит набор классов и интерфейсов, определяющих доступ к базам данных. Эти классы и методы объявлены в двух пакетах — java.sql и javax.sql ;
    • JDBC-драйвер, компонент, специфичный для каждой базы данных.

    JDBC превращает вызовы уровня API в «родные» команды того или иного сервера баз данных.

    Перечислите основные классы и интерфейсы JDBC.

    java.sql.DriverManager — позволяет загрузить и зарегистрировать необходимый JDBC-драйвер, а затем получить соединение с базой данных.

    javax.sql.DataSource — решает те же задачи, что и DriverManager, но более удобным и универсальным образом. Существуют также javax.sql.ConnectionPoolDataSource и javax.sq1.XADataSource задача которых — обеспечение поддержки пула соединений.

    java.sql.Connection — обеспечивает формирование запросов к источнику данных и управление транзакциями. Также предусмотрены интерфейсы javax.sql.PooledConnection и javax.sql.XAConnection .

    java.sql.Statement , java.sql.PreparedStatement и java.sql.CallableStatement — эти интерфейсы позволяют отправить запрос к источнику данных.

    java.sql.ResultSet — объявляет методы, которые позволяют перемещаться по набору данных и считывать значения отдельных полей в текущей записи.

    java.sql.ResultSetMetaData — позволяет получить информацию о структуре набора данных.

    java.sql.DatabaseMetaData — позволяет получить информацию о структуре источника данных.

    Перечислите основные типы данных используемые в JDBC. Как они связаны с типами Java?

    JDBC Type Java Object Type
    CHAR String
    VARCHAR String
    LONGVARCHAR String
    NUMERIC java.math.BigDecimal
    DECIMAL java.math.BigDecimal
    BIT Boolean
    TINYINT Integer
    SMALLINT Integer
    INTEGER Integer
    BIGINT Long
    REAL Float
    FLOAT Double
    DOUBLE Double
    BINARY byte[]
    VARBINARY byte[]
    LONGVARBINARY byte[]
    DATE java.sql.Date
    TIME java.sql.Time
    TIMESTAMP java.sql.Timestamp
    CLOB Clob
    BLOB Blob
    ARRAY Array
    STRUCT Struct
    REF Ref
    DISTINCT сопоставление базового типа
    JAVA_OBJECT базовый класс Java

    Опишите основные этапы работы с базой данных при использовании JDBC.

    • Регистрация драйверов;
    • Установление соединения с базой данных;
    • Создание запроса(ов) к базе данных;
    • Выполнение запроса(ов) к базе данных;

    • Обработка результата(ов);
    • Закрытие соединения с базой данных.

    Как зарегистрировать драйвер JDBC?

    Регистрацию драйвера можно осуществить несколькими способами:

    java.sql.DriverManager.registerDriver(%объект класса драйвера%) .

    Class.forName(«полное имя класса драйвера»).newInstance() .

    Class.forName(«полное имя класса драйвера») ;

    Как установить соединение с базой данных?

    Для установки соединения с базой данных используется статический вызов java.sql.DriverManager.getConnection(. ) .

    В качестве параметра может передаваться:

    • URL базы данных и набор свойств для инициализации
    • URL базы данных, имя пользователя и пароль

    В результате вызова будет установлено соединение с базой данных и создан объект класса java.sql.Connection — своеобразная «сессия», внутри контекста которой и будет происходить дальнейшая работа с базой данных.

    Какие уровни изоляции транзакций поддерживаются в JDBC?

    Уровень изолированности транзакций — значение, определяющее уровень, при котором в транзакции допускаются несогласованные данные, то есть степень изолированности одной транзакции от другой. Более высокий уровень изолированности повышает точность данных, но при этом может снижаться количество параллельно выполняемых транзакций. С другой стороны, более низкий уровень изолированности позволяет выполнять больше параллельных транзакций, но снижает точность данных.

    Во время использования транзакций, для обеспечения целостности данных, СУБД использует блокировки, чтобы заблокировать доступ других обращений к данным, участвующим в транзакции. Такие блокировки необходимы, чтобы предотвратить:

    «грязное» чтение (dirty read) — чтение данных, добавленных или изменённых транзакцией, которая впоследствии не подтвердится (откатится);

    неповторяющееся чтение (non-repeatable read) — при повторном чтении в рамках одной транзакции ранее прочитанные данные оказываются изменёнными;

    фантомное чтение (phantom reads) — ситуация, когда при повторном чтении в рамках одной транзакции одна и та же выборка дает разные множества строк.

    Уровни изоляции транзакций определены в виде констант интерфейса java.sql.Connection :

    TRANSACTION_NONE – драйвер не поддерживает транзакции;

    TRANSACTION_READ_UNCOMMITTED – позволяет транзакциям видеть несохраненные изменения данных: разрешает грязное, непроверяющееся и фантомное чтения;

    TRANSACTION_READ_COMMITTED – любое изменение, сделанное в транзакции, не видно вне неё, пока она не сохранена: предотвращает грязное чтение, но разрешает непроверяющееся и фантомное;

    TRANSACTION_REPEATABLE_READ – запрещает грязное и непроверяющееся, фантомное чтение разрешено;

    TRANSACTION_SERIALIZABLE – грязное, непроверяющееся и фантомное чтения запрещены.

    NB! Сервер базы данных может не поддерживать все уровни изоляции. Интерфейс java.sql.DatabaseMetaData предоставляет информацию об уровнях изолированности транзакций, которые поддерживаются данной СУБД.

    Уровень изоляции транзакции используемый СУБД можно задать с помощью метода setTransactionIsolation() объекта java.sql.Connection . Получить информацию о применяемом уровне изоляции поможет метод getTransactionIsolation() .

    При помощи чего формируются запросы к базе данных?

    Для выполнения запросов к базе данных в Java используются три интерфейса:

    • java.sql.Statement — для операторов SQL без параметров;
    • java.sql.PreparedStatement — для операторов SQL с параметрами и часто выполняемых операторов;
    • java.sql.CallableStatement — для исполнения хранимых в базе процедур.

    Объекты-носители интерфейсов создаются при помощи методов объекта java.sql.Connection :

    • java.sql.createStatement() возвращает объект Statement;
    • java.sql.prepareStatement() возвращает объект PreparedStatement;
    • java.sql.prepareCall() возвращает объект CallableStatement;

    Чем отличается Statement от PreparedStatement?

    • Statement: используется для простых случаев запроса без параметров.
    • PreparedStatement: предварительно компилирует запрос, который может содержать входные параметры и выполняться несколько раз с разным набором этих параметров.

    Перед выполнением СУБД разбирает каждый запрос, оптимизирует его и создает «план» (query plan) его выполнения. Если один и тот же запрос выполняется несколько раз, то СУБД в состоянии кэшировать план его выполнения и не производить этапов разборки и оптимизации повторно. Благодаря этому запрос выполняется быстрее.

    Суммируя: PreparedStatement выгодно отличается от Statement тем, что при повторном использовании с одним или несколькими наборами параметров позволяет получить преимущества заранее прекомпилированного и кэшированного запроса, помогая при этом избежать SQL Injection.

    Как осуществляется запрос к базе данных и обработка результатов?

    Выполнение запросов осуществляется при помощи вызова методов объекта, реализующего интерфейс java.sql.Statement :

    executeQuery() — для запросов, результатом которых является один набор значений, например запросов SELECT . Результатом выполнения является объект класса java.sql.ResultSet ;

    executeUpdate() — для выполнения операторов INSERT , UPDATE или DELETE , а также для операторов DDL (Data Definition Language). Метод возвращает целое число, показывающее, сколько записей было модифицировано;

    execute() – исполняет SQL-команды, которые могут возвращать различные результаты. Например, может использоваться для операции CREATE TABLE . Возвращает true , если первый результат содержит ResultSet и false , если первый результат — это количество модифицированных записей или результат отсутствует. Чтобы получить первый результат необходимо вызвать метод getResultSet() или getUpdateCount() . Остальные результаты доступны через вызов getMoreResults() , который при необходимости может быть произведён многократно.

    Объект с интерфейсом java.sql.ResultSet хранит в себе результат запроса к базе данных — некий набор данных, внутри которого есть курсор, указывающий на один из элементов набора данных — текущую запись.

    Используя курсор можно перемещаться по набору данных при помощи метода next() .

    NB! Сразу после получения набора данных его курсор находится перед первой записью и чтобы сделать её текущей необходимо вызвать метод next() .

    Содержание полей текущей записи доступно через вызовы методов getInt() , getFloat() , getString() , getDate() и им подобных.

    Как вызвать хранимую процедуру?

    Хранимые процедуры – это именованный набор операторов SQL хранящийся на сервере. Такую процедуру можно вызвать из Java-класса с помощью вызова методов объекта реализующего интерфейс java.sql.Statement .

    Выбор объекта зависит от характеристик хранимой процедуры:

    • без параметров → Statement
    • с входными параметрами → PreparedStatement
    • с входными и выходными параметрами → CallableStatement

    Если неизвестно, как была определена хранимая процедура, для получения информации о хранимой процедуре (например, имен и типов параметров) можно использовать методы java.sql.DatabaseMetaData позволяющие получить информацию о структуре источника данных.

    Пример вызова хранимой процедуры с входными и выходными параметрами:

    Как закрыть соединение с базой данных?

    Соединение с базой данной закрывается вызовом метода close() у соответствующего объекта java.sql.Connection или посредством использования механизма try-with-resources при создании такого объекта, появившегося в Java 7.

    NB! Предварительно необходимо закрыть все запросы созданные этим соединением.

  • Понравилась статья? Поделиться с друзьями:
    Все языки программирования для начинающих