Java DataSource, JDBC DataSource 示例

Java DataSource和JDBC DataSource编程是我们在Java程序中与数据库交互的方式。我们已经看到JDBC DriverManager可以用于获取关系型数据库连接。但是在实际编程中,我们希望得到的不仅仅是连接。

Java DataSource

大多数时候,我们寻求松散的连接,以便能够轻松切换数据库,连接池以进行事务管理和分布式系统支持。JDBC DataSource是在应用程序中寻求这些特性的首选方法。 Java DataSource接口位于javax.sql包中,它仅声明了两个重载的方法getConnection()getConnection(String str1,String str2)

JDBC DataSource

不同的数据库供应商有责任提供DataSource接口的不同实现。例如,MySQL JDBC驱动程序提供了DataSource接口的基本实现,使用`com.mysql.jdbc.jdbc2.optional.MysqlDataSource`类,而Oracle数据库驱动程序则使用`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

确保以上配置与您的本地设置匹配。还请确保您在项目的构建路径中包含了MySQL和Oracle数据库的JDBC jars。

Java JDBC DataSource – MySQL, Oracle 示例

让我们编写一个工厂类,我们可以使用它来获取MySQL或Oracle DataSource。

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的DataSource实现类非常相似,让我们编写一个简单的测试程序来使用这些方法并运行一些测试。

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工厂类,您会发现其中存在两个主要问题。

  1. 工厂类方法用于创建MySQL和Oracle DataSource与各自的驱动程序API紧密耦合。如果我们将来想要移除对Oracle数据库的支持,或者想要添加其他数据库的支持,都需要修改代码。
  2. 获取MySQL和Oracle DataSource的大部分代码是相似的,唯一不同的是我们正在使用的实现类。

Apache Commons DBCP API通过提供作为我们的程序与不同JDBC驱动程序之间抽象层的Java DataSource实现,帮助我们摆脱这些问题。Apache DBCP库依赖于Commons Pool库,因此请确保它们都在构建路径中,如图所示。以下是使用BasicDataSource的DataSource工厂类,它是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 DataSource。如果应用程序仅支持一个数据库,那么您甚至不需要这些逻辑。只需更改属性,就可以在不同的数据库服务器之间切换。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一起使用时。通过简单的配置,我们可以创建一个由容器本身维护的数据库连接池。大多数Servlet容器,如Tomcat和JBoss,提供了自己的Java DataSource实现,我们只需要通过简单的基于XML的配置进行配置,然后使用JNDI上下文查找获取Java DataSource并与其一起使用。这通过将连接池和管理从应用程序端移到服务器端来帮助我们,从而使我们有更多的时间为应用程序编写业务逻辑。在下一个教程中,我们将学习如何在Tomcat容器中配置DataSource并在Web应用程序中使用它。

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