Exemplo de Java DataSource, JDBC DataSource

Programação de Java DataSource e JDBC DataSource é a forma de trabalhar com banco de dados em nossos programas Java. Já vimos que JDBC DriverManager pode ser usado para obter conexões com bancos de dados relacionais. Mas quando se trata de programação real, queremos mais do que apenas conexões.

Java DataSource

Na maioria das vezes, estamos procurando um acoplamento fraco para a conectividade, para que possamos alternar facilmente entre bancos de dados, pooling de conexões para gerenciamento de transações e suporte a sistemas distribuídos. JDBC DataSource é a abordagem preferida se você estiver procurando por algum desses recursos em seu aplicativo. A interface Java DataSource está presente no pacote javax.sql e declara apenas dois métodos sobrecarregados: getConnection() e getConnection(String str1,String str2).

JDBC DataSource

É responsabilidade de diferentes fornecedores de banco de dados fornecer diferentes tipos de implementação da interface DataSource. Por exemplo, o driver JDBC do MySQL fornece uma implementação básica da interface DataSource com a classe `com.mysql.jdbc.jdbc2.optional.MysqlDataSource`, e o driver do banco de dados Oracle a implementa com a classe `oracle.jdbc.pool.OracleDataSource`. Essas classes de implementação fornecem métodos por meio dos quais podemos fornecer detalhes do servidor de banco de dados com credenciais de usuário. Alguns dos outros recursos comuns fornecidos por essas classes de implementação de DataSource JDBC são:

  • Caching de PreparedStatement para processamento mais rápido
  • Configurações de tempo limite de conexão
  • Recursos de registro
  • Limite máximo de tamanho do ResultSet

Exemplo de DataSource JDBC

Vamos criar um projeto de exemplo simples de DataSource JDBC e aprender como usar as classes de implementação básica do MySQL e Oracle DataSource para obter a conexão com o banco de dados. Nosso projeto final terá a aparência da imagem abaixo.

Configuração do Banco de Dados Java JDBC DataSource

Antes de avançarmos para nossos programas de exemplo, precisamos configurar um banco de dados com tabela e dados de amostra. A instalação do banco de dados MySQL ou Oracle está fora do escopo deste tutorial, então vou apenas configurar a tabela com dados de amostra.

-- Crie a tabela Funcionário
CREATE TABLE `Employee` (
  `empId` int(10) unsigned NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`empId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- insira alguns dados de amostra
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;

Agora vamos seguir para nossos programas em java. Para ter uma configuração de banco de dados desacoplada, vou lê-las de um arquivo de propriedades. Arquivo db.properties:

# Propriedades do banco de dados 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

# Propriedades do banco de dados 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

Certifique-se de que as configurações acima correspondam à sua configuração local. Certifique-se também de incluir os JARs JDBC do MySQL e Oracle no caminho de construção do projeto.

Java JDBC DataSource – Exemplo MySQL, Oracle

Vamos escrever uma classe de fábrica que podemos usar para obter o DataSource do MySQL ou 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;
	}
		
}

Observe que as classes de implementação DataSource do Oracle e MySQL são muito semelhantes, vamos escrever um programa de teste simples para usar esses métodos e realizar alguns testes.

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();
				}
		}
	}

}

Observe que a classe do cliente é totalmente independente de quaisquer classes específicas do banco de dados. Isso nos ajuda a ocultar os detalhes de implementação subjacentes do programa cliente e obter benefícios de acoplamento frouxo e abstração. Quando executamos o programa de teste acima, obteremos a saída abaixo.

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

Exemplo do Apache Commons DBCP

Se você olhar para a classe de fábrica Java DataSource acima, existem dois problemas principais.

  1. Os métodos da classe de fábrica para criar o MySQL e Oracle DataSource estão fortemente acoplados com as respectivas APIs de driver. Se quisermos remover o suporte ao banco de dados Oracle no futuro ou adicionar suporte a algum outro banco de dados, será necessário fazer alterações no código.
  2. A maior parte do código para obter o MySQL e Oracle DataSource é semelhante, sendo a única diferença a classe de implementação que estamos usando.

A API do Apache Commons DBCP nos ajuda a superar esses problemas, fornecendo uma implementação Java DataSource que atua como uma camada de abstração entre nosso programa e diferentes drivers JDBC. A biblioteca Apache DBCP depende da biblioteca Commons Pool, portanto, certifique-se de que ambas estão no caminho de compilação, conforme mostrado na imagem. Aqui está a classe de fábrica DataSource usando o BasicDataSource, que é a implementação simples de 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;
	}
}

Brazilian Portuguese Translation:
Como você pode ver, dependendo da entrada do usuário, é criado um DataSource MySQL ou Oracle. Se você estiver suportando apenas um banco de dados na aplicação, nem mesmo é necessário essa lógica. Basta alterar as propriedades e você pode alternar de um servidor de banco de dados para outro. O ponto chave através do qual o Apache DBCP fornece abstração é o método setDriverClassName(). Aqui está o programa cliente usando o método de fábrica acima para obter diferentes tipos de conexão.

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();
				}
		}
	}

}

Quando você executa o programa acima, a saída será a mesma do programa anterior. Se você olhar para o DataSource JDBC Java e o uso acima, também pode ser feito com o DriverManager normal. O principal benefício do Java DataSource é quando ele é usado dentro de um Contexto e com JNDI. Com configurações simples, podemos criar um Pool de Conexões de Banco de Dados que é mantido pelo próprio Contêiner. A maioria dos contêineres de servlets, como Tomcat e JBoss, fornece sua própria implementação de Java DataSource e tudo o que precisamos fazer é configurá-lo através de configurações simples baseadas em XML e depois usar a pesquisa de contexto JNDI para obter o Java DataSource e trabalhar com ele. Isso nos ajuda, cuidando do pool de conexões e gerenciamento do lado da aplicação para o lado do servidor e, assim, nos dando mais tempo para escrever a lógica de negócios para a aplicação. No próximo tutorial, aprenderemos como podemos configurar o DataSource no Contêiner Tomcat e usá-lo em uma Aplicação Web.

Source:
https://www.digitalocean.com/community/tutorials/java-datasource-jdbc-datasource-example