Trang chủHướng dẫnVí dụ về Java DataSource và JDBC DataSource trong quản lý kết nối
Java

Ví dụ về Java DataSource và JDBC DataSource trong quản lý kết nối

CyStack blog 7 phút để đọc
CyStack blog24/07/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 7 minutes

Lập trình với Java DataSource và JDBC DataSource là phương pháp được áp dụng rộng rãi khi cần xử lý cơ sở dữ liệu trong Java. Trước đây, JDBC DriverManager thường được sử dụng để thiết lập kết nối với các hệ quản trị cơ sở dữ liệu quan hệ. Tuy nhiên, trong thực tế triển khai, chỉ thiết lập kết nối thôi có thể chưa đáp ứng đủ các yêu cầu của hệ thống.

Java DataSource và JDBC DataSource

Java DataSource và JDBC DataSource trong Java

Java DataSource

Thông thường, cơ chế liên kết lỏng (loose coupling) được triển khai để đảm bảo khả năng chuyển đổi linh hoạt giữa các hệ quản trị cơ sở dữ liệu. Bên cạnh đó, sử dụng vùng kết nối (connection pooling) giúp hỗ trợ quản lý giao dịch và hệ thống phân tán. JDBC DataSource thường được sử dụng cho những mục đích này. Interface DataSource nằm trong gói javax.sql và chỉ khai báo hai phương thức nạp chồng (method overloading) là getConnection()getConnection(String username, String password).

JDBC DataSource

Việc triển khai interface DataSource là trách nhiệm của các nhà cung cấp hệ quản trị cơ sở dữ liệu khác nhau. Mỗi bên sẽ cung cấp phiên bản triển khai riêng phù hợp với sản phẩm của họ.

Chẳng hạn, MySQL JDBC Driver cung cấp phiên bản triển khai cơ bản thông qua lớp (class) com.mysql.jdbc.jdbc2.optional.MysqlDataSource, trong khi Oracle sử dụng lớp oracle.jdbc.pool.OracleDataSource. Các lớp này cung cấp các phương thức cho phép khai báo thông tin máy chủ cơ sở dữ liệu và thông tin xác thực người dùng. Bên cạnh đó, chúng còn hỗ trợ một số tính năng phổ biến như:

  • Caching các câu lệnh PreparedStatement để tăng hiệu suất xử lý
  • Thiết lập thời gian chờ cho kết nối
  • Ghi log các hoạt động kết nối
  • Giới hạn kích thước tối đa của đối tượng ResultSet

Ví dụ về JDBC DataSource

Bây giờ chúng ta sẽ tạo một dự án JDBC DataSource đơn giản và học cách sử dụng các lớp triển khai cơ bản của JDBC DataSource với MySQL và Oracle để kết nối cơ sở dữ liệu. Dự án hoàn chỉnh sẽ có cấu trúc như hình minh họa dưới đây.

Thiết lập cơ sở dữ liệu cho Java JDBC DataSource

Trước khi đi vào các ví dụ minh họa, chúng ta cần chuẩn bị cơ sở dữ liệu gồm bảng và dữ liệu mẫu. Chúng ta sẽ không đề cập đến phần cài đặt MySQL hoặc Oracle trong bài viết này nên lúc này chỉ cần tạo bảng và thêm dữ liệu mẫu vào cơ sở dữ liệu tương ứng.

--Create Employee table
CREATE TABLE `Employee` (
  `empId` int(10) unsigned NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`empId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- insert some sample data
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;

Sau đó, chúng ta sẽ bắt đầu với các chương trình Java. Để cấu hình cơ sở dữ liệu không bị ràng buộc trực tiếp vào mã nguồn, thông tin cấu hình sẽ được đọc từ file thuộc tính db.properties.

#mysql DB properties
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 DB Properties
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

Chúng ta cần đảm bảo các cấu hình trong file này phù hợp với môi trường hệ thống đang sử dụng. Đồng thời, kiểm tra và chắc chắn rằng các thư viện JDBC tương ứng cho MySQL và Oracle đã được thêm vào build path (đường dẫn biên dịch) của dự án.

Java JDBC DataSource – Ví dụ với MySQL và Oracle

Chúng ta sẽ viết một lớp factory để lấy DataSource cho MySQL hoặc 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;
	}
		
}

Lưu ý, các lớp triển khai DataSource của Oracle và MySQL khá giống nhau. Vì vậy, chúng ta sẽ viết một chương trình kiểm thử đơn giản để sử dụng các phương thức này và chạy thử một vài thao tác kết nối.

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

}

Bên cạnh đó, lớp client hoàn toàn không phụ thuộc vào bất kỳ lớp cụ thể nào của hệ quản trị cơ sở dữ liệu. Điều này giúp ẩn đi các chi tiết triển khai bên dưới khỏi chương trình client, qua đó đạt được lợi ích về liên kết lỏng và tính trừu tượng (abstraction). Khi chạy chương trình kiểm thử ở trên, chúng ta sẽ thu được kết quả như dưới đây.

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

Sử dụng Apache Commons DBCP

Khi quan sát lớp factory tạo DataSource trong ví dụ trên, chúng ta có thể nhận thấy hai vấn đề chính:

  1. Các phương thức trong lớp factory đang bị ràng buộc chặt chẽ với API của từng trình điều khiển JDBC cụ thể. Nghĩa là nếu sau này muốn loại bỏ hỗ trợ cho Oracle hoặc thêm một hệ quản trị cơ sở dữ liệu khác, chúng ta sẽ phải chỉnh sửa lại mã nguồn.
  2. Phần lớn đoạn mã để khởi tạo DataSource cho MySQL và Oracle là tương tự nhau, điểm khác biệt duy nhất chỉ nằm ở lớp triển khai được sử dụng.

Thư viện Apache Commons DBCP giúp giải quyết hai vấn đề này bằng cách cung cấp một lớp triển khai DataSource đóng vai trò như một lớp trừu tượng giữa chương trình và các driver JDBC. Thư viện DBCP phụ thuộc vào Commons Pool, vì vậy cần đảm bảo là chúng ta đã thêm cả hai thư viện vào build path như minh họa trong hình. Dưới đây là ví dụ về lớp factory sử dụng BasicDataSource, một lớp triển khai đơn giản của DataSource do Apache cung cấp.

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

Như vậy, tùy theo cấu hình đầu vào (input), hệ thống sẽ khởi tạo DataSource tương ứng cho MySQL hoặc Oracle. Trong trường hợp ứng dụng chỉ hỗ trợ với một hệ quản trị cơ sở dữ liệu duy nhất, chúng ta không cần xử lý logic phân nhánh này mà chỉ cần thay đổi các thông số trong file cấu hình là có thể chuyển đổi giữa các máy chủ cơ sở dữ liệu khác nhau. Điểm cốt lõi giúp Apache DBCP cung cấp được tính trừu tượng chính là phương thức setDriverClassName(). Dưới đây là chương trình client sử dụng phương thức factory đã xây dựng để lấy các kết nối tương ứng.

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

}

Khi chạy chương trình trên, kết quả đầu ra sẽ giống với chương trình trước đó. Nếu xét về mặt chức năng, những thao tác này hoàn toàn có thể thực hiện được bằng cách sử dụng DriverManager thông thường. Tuy nhiên, ưu điểm lớn nhất của Java DataSource chỉ thực sự phát huy khi được dùng trong ngữ cảnh (Context) cùng với JNDI.

Với một vài cấu hình đơn giản, chúng ta có thể thiết lập một pool (bể kết nối) do container trực tiếp đảm nhiệm. Hầu hết các servlet container như Tomcat hoặc JBoss đều cung cấp sẵn triển khai Java DataSource riêng. Khi đó, việc mà chúng ta cần làm chỉ là cấu hình thông qua các tệp XML và sử dụng JNDI context để tra cứu DataSource, từ đó tích hợp vào ứng dụng sao cho linh hoạt và hiệu quả. Cách tiếp cận này giúp chuyển toàn bộ trách nhiệm quản lý và tái sử dụng kết nối từ phía ứng dụng sang phía server, từ đó cho phép nhà phát triển tập trung nhiều hơn vào việc xây dựng logic nghiệp vụ.

Trong bài tiếp theo, chúng ta sẽ tìm hiểu cách cấu hình DataSource trong môi trường Tomcat và sử dụng nó trong một ứng dụng web (Web Application).

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất