מקור נתונים של Java, דוגמת JDBC DataSource

DataSource של Java ו-DataSource של JDBC הם הדרכים לעבוד עם מסדי נתונים בתוכניות Java שלנו. ראינו כבר שניתן להשתמש ב-JDBC DriverManager כדי לקבל חיבורים למסדי נתונים רלציוניים. אך כאשר מדובר בתכנות בפועל, אנחנו רוצים יותר מחיבורים בלבד.

DataSource של Java

ברוב הפעמים אנחנו מחפשים קישור גמיש כדי שנוכל להחליף מסדי נתונים בקלות, אפשרות לקבוצת חיבורים עבור ניהול עסקאות ותמיכה במערכות מבוזרות. DataSource של JDBC היא הגישה המומלצת אם אתה מחפש אחת מתכונות אלו ביישום שלך. ממשק DataSource של Java נמצא בחבילת javax.sql והוא מצהיר רק על שני שיטות מועמדות getConnection() ו-getConnection(String str1,String str2).

DataSource של JDBC

האחריות על ספקי מסדי נתונים שונים לספק יישומות שונות של ממשק DataSource. לדוגמה, מנהל MySQL JDBC מספק יישום בסיסי של ממשק DataSource עם מחלקת `com.mysql.jdbc.jdbc2.optional.MysqlDataSource`, ונהג מסד הנתונים של Oracle מיישם אותו עם מחלקת `oracle.jdbc.pool.OracleDataSource`. מחלקות היישום הללו מספקות שיטות שבאמצעותן ניתן לספק פרטי שרת מסד הנתונים יחד עם פרטי הכניסה של המשתמש. כמה מתכונות נוספות נפוצות המסופקות על ידי מחלקות יישום אלו לממשק DataSource של JDBC הן;

  • קידום המיצוא של PreparedStatement לעיבוד מהיר יותר
  • הגדרות זמן קשר של חיבור
  • תכונות לוגינג
  • סף גודל מרבי של ResultSet

דוגמה ל-JDBC DataSource

בואו ליצור פרויקט דוגמה פשוטה של JDBC DataSource ונלמד איך להשתמש במחלקות יישום של המימוש הבסיסי של MySQL וOracle DataSource כדי לקבל חיבור למסד הנתונים. הפרויקט הסופי שלנו ייראה כמו התמונה למטה.

מקור הנתונים של Java JDBC – הגדרת מסד נתונים

לפני שנכנס לתוכניות הדוגמה שלנו, נצטרך להגדיר מסד נתונים עם טבלה ונתוני דוגמה. התקנת מסד נתונים של MySQL או Oracle נמצאת מחוץ לטווח של המדריך הזה, כך שאני פשוט אגדיר טבלה עם נתוני דוגמה.

-- צור טבלת עובדים
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 מוכלים בנתיב הבנייה של הפרוייקט.

מקור הנתונים של Java JDBC – דוגמה ל 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;
	}
		
}

שימו לב ששני המחלקות ליישום DataSource של 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();
				}
		}
	}

}

שים לב שמחלקת הלקוח (Client) היא לגמרי תלת-גורמת לכל מחלקות המסד נתונים הספציפיות. זה עוזר לנו להסתיר את פרטי היישום המתואר מתחת לממשק ולהשיג יתרונות של חיבור פתוח והפשטת ההסתרה. כאשר אנו מפעילים את התכנית הבדיקה לעיל, נקבל את הפלט הבא.

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 לעיל, ישנם שני בעיות עיקריות עימה.

  1. שיטות מחלקת המפענח ליצירת מקורי נתונים של MySQL ו-Oracle קשורות יתר עם ממשק ה- API של הנהג הרלוונטי. אם נרצה להסיר תמיכה במסד הנתונים של Oracle בעתיד או להוסיף תמיכה במסד נתונים אחר, יידרש שינוי בקוד.
  2. רוב הקוד לקבלת מקורי נתונים של MySQL ו-Oracle דומה, היחיד השונה הוא המחלקה המיושמת שאנו משתמשים בה.

ספריית Apache Commons DBCP עוזרת לנו להיפטר מבעיות אלו על ידי ספקת מימוש של DataSource ב-Java העובד כשכבת ההסתרה בין התוכנית שלנו לבין מקודי הנהיגה השונים של JDBC. ספריית Apache DBCP תלויה בספריית Commons Pool, לכן יש לוודא ששתי הספריות נמצאות בנתיב הבנייה כפי שמוצג בדימוי. כאן יש מחלקת מקור הנתונים שמשתמשת ב-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;
	}
}

כפי שאתה רואה, תלוי בקלט המשתמש, נוצר DataSource של 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 הוא כאשר הוא משמש בתוך Context ועם JNDI. עם תצורות פשוטות אנו יכולים ליצור בריכת חיבורי מסד נתונים שמתוחזקת על ידי המעטפת עצמה. רוב מנועי הסרוולטים כגון Tomcat ו-JBoss מספקים מימוש משלהם של Java DataSource וכל מה שאנו צריכים הוא להגדיר אותו דרך קבצי XML פשוטים ולאחר מכן להשתמש בחיפוש בהקשר JNDI כדי לקבל את Java DataSource ולעבוד איתו. זה עוזר לנו על ידי טיפול בשחבור חיבורים וניהול מצד האפליקציה שלנו עד לצד השרת ולכן נותן לנו יותר זמן לכתיבת הלוגיקה העסקית עבור האפליקציה. בשיעור הבא, נלמד איך ניתן להגדיר DataSource במעטפת Tomcat ולהשתמש בו באפליקציה אינטרנטית.

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