Для чего нужен drivermanager
На этот раз я хотел бы уделить внимание работе с базами данных с помощью JDBC API.
Спор под названием Hibernate (точнее JPA) против JDBC оставим в стороне. Оба подхода имеют право на существование. Если хотите услышать мое личное мнение по этому поводу, то загляните в конец статьи.
А сейчас давайте рассмотрим следующие вопросы:
DriverManager и JDBC Driver
Во всех примерах подключения к базе данных в Интернете вы обязательно встретите эти строки:
Обычно на этом повествование про драйвер и DriverManager заканчивается. Ну а мы копнем чуть глубже.
Все основные сущности в JDBC API, с которыми вам предстоит работать, являются интерфейсами:
JDBC драйвер конкретной базы данных как раз и предоставляет реализации этих интерфейсов.
Так а зачем же вызов Class.forName()?
Если посмотреть исходный код реализации любого драйвера он будет содержать статический блок инициализации такого вида:
Вызов Class.forName загружает класс и этим гарантирует выполнение статического блока инициализации, а значит и регистрацию драйвера в DriverManager.
Соединение к базе данных
В статье я предлагаю воспользоваться легковесной базой данных, написанной на Java, под названием H2 Database. В данный момент для нас преимущество ее использования состоит в том, что скачав джарку здесь вы получаете сразу и саму базу данных, и драйвер для подключения к ней, что для обучения очень удобно.
Подробнее об H2 я обязательно расскажу в отдельной статье, а пока что создадим соединение к базе данных:
Таким образом, мы получили реализацию интерфейса java.sql.Connection для нашей базы данных.
Полный код всех примеров можно найти в конце статьи.
Используем Statement и ResultSet
На основании соединения можно получить объект java.sql.Statement для выполнения запросов к базе.
В результате выполнения этого фрагмента кода будет создана таблица user с двумя колонками id и name.
Statement можно использовать для выполнения любых запросов, будь то DDL, DML, либо обычные запросы на выборку данных.
Объекты 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
Лично я часто использую DatabaseMetaData для модификации схемы базы данных программным способом, например:
После добавления новой функциональности можно проверить, а не созданы ли уже соответствующие объекты, и в случае необходимости модифицировать схему.
Заключение
Конечно, JDBC API создано далеко не идеальным. Например, SQLException является checked исключением и его повсюду надо тянуть или оборачивать; работа с PreparedStatement достаточно неудобная, как мы уже видели.
Но в подавляющем большинстве случаев я использую именно JDBC для свои приложений, так как JDBC дает максимальную гибкость и эффективность. Возможно с Hibernate вы сэкономите один день, так как вам не придется писать код для создания схемы, а так же запросы для чтения и записи объектов. Но что такое один день по сравнению со временем существования приложения? К тому же практика показывает, что периодически Hibernate преподносит разрабочикам интересные челенджи, решение которых может забрать не только время, но и нервы
Полный исходный код примеров из статьи можно найти здесь SqlExamples.java.
Любое современное приложение работает с разного рода данными. Получает их, обрабатывает, анализирует, хранит. Сами же эти данные тоже должны где-то хранится. Так вот, данные хранятся в специальных базах данных, управляемых разного рода СУБД (Системами Управления Базами Данных), а JDBC (Java DataBase Connectivity) – Java API для взаимодействия с СУБД. Из некоторых важных характеристик JDBC API стоит отметить, то что он абстрактный (абстрагирует разработчика от нюансов конкретной СУДБ). При этом сам разработчик может использовать специфические детали СУБД.
Как JDBC взаимодействует с базой данных?
После прочтения первого абзаца этот вопрос возникает естественным образом. Действительно, как? Ведь существует огромное количество баз данных (Oracle, PostgreSQL, MySQL и т.д. ), каждая из которых имеет свое собственное API, даже разные синтаксисы SQL! Для взаимодействия с базой данных необходимо использовать JDBC Driver, который предоставляется разработчиками самой базы данных. Т.е. при работе с Oracle, необходимо использовать драйвер предоставляемый Oracle. Конечно, это необязательно. Никто не запрещает вам сделать свой собственный JDBC Driver с Блэк-джэком и … ну вы поняли 🙂 Этот подход описывает один из паттернов “Банды 4-х” – Bridge. Будучи разработчиком вы врятли будите его часто использовать.
Как вы можете видеть JDBC Driver реализует нативный протокол, по которому происходит обращение к серверу базы данных. Причем мы работает с интерфейсом JDBC. Который уже работает с драйвером. Как раз это позволяет нам, быть устойчивыми к изменению СУБД. Поменять Oracle на PostgreSQL? Легко! Меняем только драйвер, реализацию не трогаем. Так же может быть ситуация, когда нам необходимо использовать несколько драйверов. Поэтому в JVM есть возможность централизовано хранить их. Для этого необходимо создать объект класса DriverManager( по сути Singletone) и зарегистрировать драйвера в менеджере.
DriverManager
Работа протекает таким образом, что разработчику обращается к драйверу с помощью метода getConnection() в параметрах которого передает “свойства” базы данных(DB_URL). Ниже подробнее рассмотрим этот метод. Далее DriverManager предоставляет экземпляр драйвера, который соответствует переданным свойствам. Отмети, что если в менеджере находится несколько одинаковых драйверов, то возвращен будет только первый соотвествующий входным параметрам getConnection(). Для того, чтобы использовать DriverManager, необходимо зарегистрировать в нем ваши драйвера (только если вы работаете с JDBC 4, это произойдет автоматически). Для этого вам предоставляется на выбор несколько вариантов:
Установка соединения с базой данных
Когда же мы, наконец установили драйвер, зарегистрировали его в DriverManager, мы устанавливаем соединение с базой данных. Как написано выше, для получения соединения нам необходимо вызвать у менеджера метод getConnection(). Метод реализован в трех вариантах.
Русские Блоги
Разница между DriverManager и DataSource и тестовым кодом JDBC
В чем разница между DriverManager и DataSource, подключающимся к базе данных?
Традиционное соединение jdbc DriverManager, после регистрации через Class.forName («XXX»), вы можете получить соединение через DriverManager.getConnection ().
Источник данных построен на основе службы JNDI и требует, чтобы сервер приложений сконфигурировал источник данных. Сначала необходимо зарегистрировать источник данных (как правило, в /META-INF/context.xml), а затем обратиться к этому источнику данных в файле web.xml, вы можете использовать DataSource.getConnection. () Получить соединение, ссылку на конкретную операцию (раздел Ресурсы JNDI в каталоге tomcat)
В чем разница между источником данных и пулом DBCP?
Когда J2EE-сервер запущен, будет установлено определенное количество подключений к пулу, и оно будет поддерживать как минимум это количество подключений к пулу. Когда клиентская программа должна подключиться, драйвер пула возвращает неиспользуемое подключение к пулу и записывает его как занятое. Если в данный момент нет свободных соединений, драйвер пула создает определенное количество соединений, количество новых соединений определяется параметрами конфигурации. Когда вызов подключения к используемому пулу завершен, драйвер пула записывает эту таблицу подключений как неактивную, и другие вызовы могут использовать это подключение.
Эквивалент инструмента, оптимизированного для DataSource
Пример настройки источника данных весной, xml выглядит следующим образом:
В случае большого количества посещений и большого параллелизма, несомненно, следует использовать пул соединений BasicDataSource, поскольку благодаря функции пула соединений и эффективность, и использование ресурсов лучше, чем DriverManagerDataSource.
Руководство по JDBC. Соединение.
В прошлом уроке мы изучили понятие драйвера JDBC и его типы. После того, как мы установили необходимый драйвер мы можем создать соединение с базой данных (далее – БД).
Для того, чтобы установить соединение с БД, нам необходимо выполнить следующие шаги:
Рассмотрим каждый шаг по отдельности.
Импортирование пакета JDBC
Для импорта пакета JDBC мы используем стандартное ключевое слово import, которое говорит компилятору подключить необходимые классы.
Для подключения JDBC нам необходимо подключить пакет java.sql.*
В коде это выглядит таким образом:
Регистрация JDBC драйвера
После импорта JDBC мы должны зарегистрировать наш драйвер перед тем, как его использовать. Это процесс, с помощью которого файл класса драйвера загружается в память. После этого он может быть использован, как реализация интерфейса JDBC.
Существует два способа регистрации драйвера.
DriverManager.registerDriver()
В этом случае мы используем статический метод DriverManager.registerDriver() для регистрации драйвера.
В коде это выглядит следующим образом:
Class.forName()
Этот способ является наиболее распространённым. Мы используем метод Class.forName() для динамической загрузки класса драйвера в память, после чего происходит его автоматическая регистрация.
Данный способ является предпочтительным, так как он обеспечивает конфигурируемую и переносимую регистрацию драйверов.
В коде это выглядит, примерно, таким образом:
Передача информации о БД
После того, как мы зарегистрировали наш драйвер, мы можем установить соединение, используется метод DriverManager.getConnection().
Этот метод имеет три перегруженных варианта:
Как мы видим, каждый из этих методов требует URL нашей БД. Т.е. нам необходимо передать информацию о нашей БД.
Для различных БД URL различен.
Driver name: com.mysql.jdbc.Driver
Driver name: oracle.jdbc.driver.OracleDriver
Создание соединения
После того, как мы передали всю необходимую информацию, мы можем создать физическое соединение с БД.
Рассмотрим пример создания соединения с БД MySQL:
Закрытие соединения
После того, как закончим работу с нашей программой нам необходимо закрыть все соединения и освободить ресурсы. Если мы не сделаем этого вручную, это будет сделано сборщиком мусора при уничтожении объектов, которые не используются.
Но полагаться на уборщик мусора – это крайне плохая идея и пример дурного тона.
В коде это выглядит так:
В этом уроке мы рассмотрели соединение и разобрали все этапы его создания по отдельности.
В следующем уроке мы изучим такую сущность, как утверждения (Statements).
Работа с подключением
Скачать драйвер JDBC
В следующих разделах приведены примеры различных способов соединения с базой данных SQL Server с помощью класса SQLServerConnection драйвера Microsoft JDBC Driver для SQL Server.
При возникновении неполадок с соединением с SQL Server с помощью драйвера JDBC см. раздел Профилактика подключений, где можно найти сведения по их устранению.
Установка подключения с использованием класса DriverManager
Простейший способ соединения с базой данных SQL Server — загрузка драйвера JDBC и вызов метода getConnection класса DriverManager:
По этой методике подключение к базе данных будет создано с помощью первого доступного драйвера из списка драйверов, способных успешно подсоединиться к данному URL-адресу.
При использовании библиотеки классов sqljdbc4.jar приложениям не обязательно явно регистрировать или загружать драйвер с помощью метода Class.forName. При вызове метода getConnection класса DriverManager подходящий драйвер выбирается из набора зарегистрированных драйверов JDBC. Дополнительные сведения об использовании JDBC см. в разделе «Использование драйвера JDBC».
Установка подключения с использованием класса SQLServerDriver
Если нужно указать конкретный драйвер из списка драйверов для DriverManager, то можно создать подключение к базе данных с помощью метода connect класса SQLServerDriver:
Установка подключения с использованием класса SQLServerDataSource
При необходимости создать соединение с помощью класса SQLServerDataSource можно использовать различные методы задания класса, после чего вызывается метод getConnection:
Установка подключения, предназначенного для конкретного источника данных
Создать подключение к базе данных, целью которого является конкретный источник данных, можно несколькими способами. Каждый способ зависит от свойств, задаваемых с помощью URL-адреса соединения.
Подключиться к экземпляру по умолчанию на удаленном сервере можно следующим образом:
Подключиться к конкретному порту на сервере можно следующим образом:
Подключиться к именованному экземпляру на сервере можно следующим образом:
Подключиться к конкретной базе данных на сервере можно следующим образом:
Дополнительные примеры URL-адресов подключений см. в статье о создании URL-адреса подключения.
Установка подключения с настраиваемым временем сохранения учетных данных
Если приходится подстраиваться под нагрузку сервера или сети, можно создать соединение с заданным временем сохранения учетных данных в секундах:
Установка подключения с идентификацией на уровне приложения
Если для работы требуется ведение журнала и профилирование, то необходимо идентифицировать соединение по инициировавшему его приложению:
Закрытие подключения
Подключение к базе данных можно явно закрыть путем вызова метода close класса SQLServerConnection:
Освобождение ресурсов базы данных, используемых объектом SQLServerConnection, или возврат соединения в пул соединений в сценариях с пулами.
Вызов метода close также приведет к откату любой ожидающей выполнения транзакции.