Java DataSource и программирование JDBC DataSource – это способ работы с базой данных в наших java-программах. Мы уже видели, что JDBC DriverManager можно использовать для получения соединений с реляционной базой данных. Но когда речь идет о реальном программировании, мы хотим большего, чем просто соединения.
Java DataSource
В большинстве случаев нам нужна слабая связь для подключения, чтобы мы могли легко переключаться между базами данных, пулы соединений для управления транзакциями и поддержка распределенных систем. JDBC DataSource – предпочтительный подход, если вы ищете любые из этих функций в своем приложении. Интерфейс Java DataSource находится в пакете javax.sql
и объявляет только два перегруженных метода: getConnection()
и getConnection(String str1,String str2)
.
JDBC DataSource
Это ответственность различных поставщиков баз данных предоставлять различные виды реализации интерфейса DataSource. Например, драйвер JDBC для MySQL предоставляет базовую реализацию интерфейса DataSource с классом \texttt{com.mysql.jdbc.jdbc2.optional.MysqlDataSource}, а драйвер базы данных Oracle реализует его с помощью класса \texttt{oracle.jdbc.pool.OracleDataSource}. Эти классы реализации предоставляют методы, с помощью которых мы можем предоставить сведения о сервере баз данных с учетными данными пользователя. Некоторые из других общих функций, предоставляемых этими классами реализации JDBC DataSource, включают;
- Кэширование PreparedStatement для ускоренной обработки
- Настройки времени ожидания подключения
- Возможности ведения журнала
- Порог максимального размера ResultSet
Пример JDBC DataSource
Давайте создадим простой проект с примером JDBC DataSource и узнаем, как использовать базовые классы реализации MySQL и Oracle DataSource для получения подключения к базе данных. Наш конечный проект будет выглядеть как на изображении ниже.
Настройка базы данных Java JDBC DataSource
Прежде чем мы перейдем к нашим примерам программ, нам нужно создать базу данных с таблицей и примерными данными. Установка базы данных MySQL или Oracle выходит за рамки этого руководства, поэтому я просто настрою таблицу с примерными данными.
-- Создаем таблицу Employee
CREATE TABLE `Employee` (
`empId` int(10) unsigned NOT NULL,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`empId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Вставляем несколько примерных данных
INSERT INTO `Employee` (`empId`, `name`)
VALUES
(1, 'Pankaj'),
(2, 'David');
commit;
CREATE TABLE "EMPLOYEE"
(
"EMPID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(10 BYTE) DEFAULT NULL,
PRIMARY KEY ("EMPID")
);
Insert into EMPLOYEE (EMPID,NAME) values (10,'Pankaj');
Insert into EMPLOYEE (EMPID,NAME) values (5,'Kumar');
Insert into EMPLOYEE (EMPID,NAME) values (1,'Pankaj');
commit;
Теперь перейдем к нашим java-программам. Чтобы настройка базы данных была слабо связанной, я буду считывать их из файла свойств. Файл db.properties:
# Свойства БД MySQL
MYSQL_DB_DRIVER_CLASS=com.mysql.jdbc.Driver
MYSQL_DB_URL=jdbc:mysql://localhost:3306/UserDB
MYSQL_DB_USERNAME=pankaj
MYSQL_DB_PASSWORD=pankaj123
# Свойства БД Oracle
ORACLE_DB_DRIVER_CLASS=oracle.jdbc.driver.OracleDriver
ORACLE_DB_URL=jdbc:oracle:thin:@localhost:1521:orcl
ORACLE_DB_USERNAME=hr
ORACLE_DB_PASSWORD=oracle
Убедитесь, что вышеуказанные конфигурации соответствуют вашей локальной настройке. Также убедитесь, что у вас включены в путь сборки проекта библиотеки JDBC для MySQL и Oracle DB.
Пример Java JDBC DataSource – MySQL, Oracle
Давайте напишем фабричный класс, который мы можем использовать для получения источника данных MySQL или Oracle.
package com.journaldev.jdbc.datasource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import oracle.jdbc.pool.OracleDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class MyDataSourceFactory {
public static DataSource getMySQLDataSource() {
Properties props = new Properties();
FileInputStream fis = null;
MysqlDataSource mysqlDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
mysqlDS = new MysqlDataSource();
mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));
mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));
mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
}
return mysqlDS;
}
public static DataSource getOracleDataSource(){
Properties props = new Properties();
FileInputStream fis = null;
OracleDataSource oracleDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
oracleDS = new OracleDataSource();
oracleDS.setURL(props.getProperty("ORACLE_DB_URL"));
oracleDS.setUser(props.getProperty("ORACLE_DB_USERNAME"));
oracleDS.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return oracleDS;
}
}
Обратите внимание, что классы реализации источника данных Oracle и MySQL очень похожи, давайте напишем простую тестовую программу, чтобы использовать эти методы и провести некоторые тесты.
package com.journaldev.jdbc.datasource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
public class DataSourceTest {
public static void main(String[] args) {
testDataSource("mysql");
System.out.println("**********");
testDataSource("oracle");
}
private static void testDataSource(String dbType) {
DataSource ds = null;
if("mysql".equals(dbType)){
ds = MyDataSourceFactory.getMySQLDataSource();
}else if("oracle".equals(dbType)){
ds = MyDataSourceFactory.getOracleDataSource();
}else{
System.out.println("invalid db type");
return;
}
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
while(rs.next()){
System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Обратите внимание, что класс клиента полностью независим от любых специфических для базы данных классов. Это помогает нам скрыть детали реализации от клиентской программы и получить преимущества связывания и абстракции. Когда мы запускаем вышеуказанную тестовую программу, мы получим следующий вывод.
Employee ID=1, Name=Pankaj
Employee ID=2, Name=David
**********
Employee ID=10, Name=Pankaj
Employee ID=5, Name=Kumar
Employee ID=1, Name=Pankaj
Пример Apache Commons DBCP
Если вы посмотрите на вышеуказанный класс фабрики Java DataSource, вы увидите две основные проблемы.
- Методы класса фабрики для создания MySQL и Oracle DataSource тесно связаны с соответствующим API драйвера. Если мы захотим удалить поддержку базы данных Oracle в будущем или добавить поддержку другой базы данных, это потребует изменения кода.
- Большая часть кода для получения MySQL и Oracle DataSource аналогична, единственное отличие – это класс реализации, который мы используем.
API Apache Commons DBCP помогает нам избавиться от этих проблем, предоставляя реализацию Java DataSource, которая работает как слой абстракции между нашей программой и различными JDBC-драйверами. Библиотека Apache DBCP зависит от библиотеки Commons Pool, поэтому убедитесь, что они оба находятся в пути сборки, как показано на изображении. Вот класс фабрики DataSource, использующий BasicDataSource, который является простой реализацией DataSource.
package com.journaldev.jdbc.datasource;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
public class DBCPDataSourceFactory {
public static DataSource getDataSource(String dbType){
Properties props = new Properties();
FileInputStream fis = null;
BasicDataSource ds = new BasicDataSource();
try {
fis = new FileInputStream("db.properties");
props.load(fis);
}catch(IOException e){
e.printStackTrace();
return null;
}
if("mysql".equals(dbType)){
ds.setDriverClassName(props.getProperty("MYSQL_DB_DRIVER_CLASS"));
ds.setUrl(props.getProperty("MYSQL_DB_URL"));
ds.setUsername(props.getProperty("MYSQL_DB_USERNAME"));
ds.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
}else if("oracle".equals(dbType)){
ds.setDriverClassName(props.getProperty("ORACLE_DB_DRIVER_CLASS"));
ds.setUrl(props.getProperty("ORACLE_DB_URL"));
ds.setUsername(props.getProperty("ORACLE_DB_USERNAME"));
ds.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
}else{
return null;
}
return ds;
}
}
Как видите, в зависимости от ввода пользователя создается либо источник данных MySQL, либо Oracle. Если вы поддерживаете только одну базу данных в приложении, вам даже не нужна эта логика. Просто измените свойства, и вы сможете переключиться с одного сервера баз данных на другой. Основной момент, через который Apache DBCP обеспечивает абстракцию, это метод setDriverClassName(). Вот клиентская программа, использующая вышеупомянутый фабричный метод для получения различных типов соединений.
package com.journaldev.jdbc.datasource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
public class ApacheCommonsDBCPTest {
public static void main(String[] args) {
testDBCPDataSource("mysql");
System.out.println("**********");
testDBCPDataSource("oracle");
}
private static void testDBCPDataSource(String dbType) {
DataSource ds = DBCPDataSourceFactory.getDataSource(dbType);
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
while(rs.next()){
System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
При запуске вышеуказанной программы вывод будет таким же, как и ранее. Если рассмотреть использование Java JDBC DataSource и вышеуказанное использование, то это также можно сделать с помощью обычного DriverManager. Основное преимущество Java DataSource заключается в том, что она используется в контексте и с JNDI. С помощью простых конфигураций мы можем создать пул соединений с базой данных, который поддерживается самим контейнером. Большинство контейнеров сервлетов, таких как Tomcat и JBoss, предоставляют собственную реализацию Java DataSource, и все, что нам нужно, – это настроить ее с помощью простых конфигураций на основе XML, а затем использовать поиск контекста JNDI, чтобы получить Java DataSource и работать с ним. Это помогает нам, перекладывая ответственность за пул соединений и управление с нашей стороны приложения на серверную сторону, и тем самым дает нам больше времени для написания бизнес-логики для приложения. В следующем уроке мы узнаем, как настроить DataSource в контейнере Tomcat и использовать его в веб-приложении.
Source:
https://www.digitalocean.com/community/tutorials/java-datasource-jdbc-datasource-example