7.1 พูลการเชื่อมต่อ
วันนี้เราจะเรียนรู้วิธีการทำงานกับฐานข้อมูลอย่างมืออาชีพมากยิ่งขึ้น และตอนนี้เราจะพูดถึงกลุ่มเธรดหรือกลุ่มการเชื่อมต่อในภาษาอังกฤษ
การเชื่อมต่อกับฐานข้อมูลจะใช้เวลาสักครู่ โดยเฉพาะอย่างยิ่งถ้าฐานข้อมูลเป็นแบบรีโมต หากเราเชื่อมต่อกับฐานข้อมูลสำหรับแต่ละคำขอ การตอบสนองของแอปพลิเคชันของเราจะช้าอย่างไม่น่าเชื่อ ไม่ต้องพูดถึงทรัพยากรที่จะใช้
เพื่อแก้ปัญหาดังกล่าว จึงเสนอให้จัดเก็บการเชื่อมต่อกับฐานในบางชุด ซึ่งเรียกว่าเธรดพูล
เมื่อเราร้องขอการเชื่อมต่อใหม่ กลุ่มการเชื่อมต่อจะสร้างการเชื่อมต่อ และเมื่อปิด จะไม่ปิด แต่จะบันทึกไว้ในกลุ่มการเชื่อมต่อ และถ้าเราร้องขอการเชื่อมต่อจากกลุ่มการเชื่อมต่ออีกครั้ง มันจะให้หนึ่งในอันเก่าแก่เราแทนที่จะสร้างอันใหม่
อันที่จริงแล้ว แอปพลิเคชันทำงานผ่านไดรเวอร์พิเศษ ซึ่งเป็นตัวตัดสำหรับไดรเวอร์ JDBC ปกติ และมีฟังก์ชันเพิ่มเติมสำหรับการทำงานกับพูล สถานการณ์นี้สามารถแสดงได้ดังนี้:

โปรแกรมเมอร์สามารถตั้งค่าสำหรับพูลการเชื่อมต่อได้ด้วยตนเอง: จำนวนการเชื่อมต่อที่ใช้งานอยู่ การหมดเวลา ฯลฯ
สำหรับสถานการณ์ที่รุนแรงโดยเฉพาะอย่างยิ่ง คุณสามารถเขียนกลุ่มการเชื่อมต่อของคุณเอง: คลาสที่จะมีรายการของการเชื่อมต่อ มันจะแทนที่ฟังก์ชันปิด ซึ่งจะคืนการเชื่อมต่อกลับไปยังรายการ และจะมีสารพัดอื่นๆ อีกมากมาย เช่น ตัวจับเวลาการเชื่อมต่อแบบเปิด เมื่อไม่มีการเชื่อมต่อเป็นเวลานาน การเชื่อมต่อจะถูกปิด
7.2* อินเทอร์เฟซ DataSource และ ConnectionPoolDataSource
พูลเธรดมักจะทำงานควบคู่กับอ็อบเจ็กต์ DataSource วัตถุนี้สามารถคิดได้ว่าเป็นนามธรรมของฐานข้อมูลระยะไกล ชื่อ Data Source สามารถแปลได้อย่างแท้จริงว่า Data Source ซึ่งเป็นการบอกใบ้
วัตถุ DataSource ใช้เพื่อรับการเชื่อมต่อทางกายภาพกับฐานข้อมูลและเป็นทางเลือกแทน DriverManager ไม่จำเป็นต้องลงทะเบียนไดรเวอร์ JDBC คุณจะต้องตั้งค่าพารามิเตอร์ที่เหมาะสมเพื่อสร้างการเชื่อมต่อและดำเนินการเมธอด getConnection().
เมื่อสร้างอ็อบเจกต์ประเภท DataSource แบบโลคัล (โดยตรงในแอ็พพลิเคชัน) พารามิเตอร์การเชื่อมต่อจะถูกตั้งค่าโดยเมธอดที่เหมาะสมซึ่งจัดเตรียมโดยผู้ให้บริการไดรเวอร์ JDBC เมธอดเหล่านี้ไม่ได้กำหนดโดยอินเทอร์เฟซ DataSource เนื่องจากพารามิเตอร์สำหรับการเชื่อมต่อกับ DBMS จากผู้ขายที่แตกต่างกันอาจแตกต่างกันทั้งประเภทและจำนวน (เช่น DBMS บางตัวไม่จำเป็นต้องระบุประเภทของไดรเวอร์หรือโปรโตคอลเครือข่าย)
ดังนั้น เมื่อทำงานกับ Oracle DBMS เพื่อใช้ set และ get method ที่สอดคล้องกัน จึงจำเป็นต้องได้รับอ็อบเจกต์ประเภท OracleDataSource ซึ่งเป็นอินสแตนซ์ของคลาสชื่อเดียวกันที่ใช้อินเทอร์เฟซ DataSource ดังนั้น วิธีการสร้างออบเจกต์ประเภท DataSource นี้ทำให้โค้ดของคุณพกพาได้น้อยลงและขึ้นอยู่กับการใช้งานไดรเวอร์ที่เฉพาะเจาะจงน้อยลง
ต่อไปนี้คือตัวอย่างโค้ดที่แสดงการใช้วัตถุประเภท DataSource ในเครื่อง
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.*;
public class DataSource {
public static void main(String[] args) {
try {
OracleDataSource ods = new OracleDataSource();
ods.setUser("root");
ods.setPassword("secret");
ods.setDriverType("thin");
ods.setDatabaseName("test");
ods.setServerName("localhost");
ods.setPortNumber(1521);
Connection connection = ods.getConnection();
System.out.println("Connection successful!!!");
} catch (SQLException se) {
se.printStackTrace();
}
System.out.println("Goodbye!");
}
}
อินเทอร์เฟซ 7.3 * JNDI
ความสามารถทั้งหมดของออบเจกต์ประเภท DataSource นั้นแสดงร่วมกับการใช้อินเทอร์เฟซ JNDI JNDI เป็นบริการพิเศษ (เช่น ไดเร็กทอรี) สำหรับแอปพลิเคชันเซิร์ฟเวอร์ขนาดใหญ่ที่อนุญาตให้บริการหนึ่งสร้างการเชื่อมต่อกับอีกบริการหนึ่ง
การใช้ชื่อและบริการไดเร็กทอรีทำให้คุณสามารถจัดเก็บอ็อบเจ็กต์ประเภท DataSource ที่สร้างไว้ก่อนหน้านี้โดยผู้ดูแลระบบพร้อมพารามิเตอร์การเชื่อมต่อที่กำหนดไว้ล่วงหน้า ต่อไปนี้เป็นชื่อคุณสมบัติมาตรฐาน (พารามิเตอร์) ที่พัฒนาโดย Sun:
ชื่อทรัพย์สิน | ชนิดข้อมูลจาวา | วัตถุประสงค์ |
---|---|---|
ชื่อฐานข้อมูล | สตริง | ชื่อฐานข้อมูล |
ชื่อเซิร์ฟเวอร์ | สตริง | ชื่อเซิร์ฟเวอร์ |
ผู้ใช้ | สตริง | ชื่อผู้ใช้ (ID) |
รหัสผ่าน | สตริง | รหัสผ่านผู้ใช้ |
หมายเลขพอร์ต | นานาชาติ | หมายเลขพอร์ตเซิร์ฟเวอร์ DBMS |
การรวมกันของอินเทอร์เฟซ DataSource และ JNDI มีบทบาทสำคัญในการพัฒนาแอปพลิเคชันระดับองค์กรแบบหลายชั้นโดยใช้เทคโนโลยีส่วนประกอบ J2EE
หากคุณใช้อินเทอร์เฟซ DataSource และ JNDI ร่วมกันในโค้ดแอปพลิเคชันของคุณ คุณต้องขออ็อบเจ็กต์ประเภท DataSource จากบริการตั้งชื่อและไดเร็กทอรีเท่านั้น ในกรณีนี้ รายละเอียดของการเชื่อมต่อและรหัสโปรแกรมที่ขึ้นอยู่กับการใช้งานเฉพาะของไดรเวอร์จะถูกซ่อนจากแอปพลิเคชันในวัตถุที่จัดเก็บไว้ในชื่อและบริการไดเร็กทอรี
ดังนั้น การแชร์อ็อบเจ็กต์ประเภท DataSource และ JNDI จึงเกี่ยวข้องกับสองขั้นตอนที่ดำเนินการโดยอิสระจากกัน:
- คุณต้องจัดเก็บวัตถุที่มีชื่อประเภท DataSource ในการตั้งชื่อและบริการไดเร็กทอรีโดยใช้
Context.bind()
ไฟล์javax.naming
. - ขอวัตถุประเภท DataSource จากบริการตั้งชื่อและไดเร็กทอรีในแอปพลิเคชันโดยใช้ไฟล์
Context.lookup()
. หลังจากนั้นคุณสามารถใช้วิธีการนี้DataSource.getConnection()
เพื่อเชื่อมต่อกับฐานข้อมูลได้
ต่อไปนี้เป็นตัวอย่างของการใช้อินเทอร์เฟซ JNDI และอ็อบเจ็กต์ประเภท OracleDataSource ร่วมกัน
// Create a key JNDI object
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:JNDI");
Context ctx = new InitialContext(env);
// Get the DataSource object by its name
DataSource ods = (DataSource) ctx.lookup("myDatabase");
// Get the Connection from the DataSource object
Connection connection = ods.getConnection();
System.out.println("Connection successful!!!");
เราจะไม่วิเคราะห์งานของ JNDI ซึ่งอยู่นอกเหนือขอบเขตของหลักสูตรนี้ ฉันแค่อยากให้คุณรู้ว่าวิธีการนี้พบได้ทั่วไปในแอปพลิเคชันขนาดใหญ่ อย่าหลงทางหากคุณเห็นโค้ดแบบนี้ในอนาคต
ไม่สำคัญว่ามันทำงานอย่างไร คุณเพียงแค่ต้องรู้ว่าด้วยบริการ JNDI คุณสามารถรับวัตถุพร็อกซีของบริการใดๆ ที่ลงทะเบียนในไดเร็กทอรีบริการได้ นี่คือวิธีที่คุณได้รับวัตถุ DataSource และใช้เพื่อทำงานกับฐานข้อมูล
7.4 ตัวอย่างการเชื่อมต่อพูล
กลับไปที่จุดเริ่มต้น - กลุ่มการเชื่อมต่อ

โปรแกรมเมอร์ Java ในโปรแกรมของพวกเขามักจะใช้ไลบรารีที่มีการใช้งานพูลการเชื่อมต่อที่หลากหลาย ในหมู่พวกเขามีสามยอดนิยม:
- อาปาเช่คอมมอนส์ DBCP
- C3PO
- ฮิคาริซีพี
โครงการ Apache เป็นโครงการแรกที่สร้างกลุ่มการเชื่อมต่อที่ดี นอกจากนี้ยังใช้ภายในเว็บเซิร์ฟเวอร์ Tomcat ตัวอย่างของการทำงานร่วมกับมัน:
public class DBCPDataSource {
private static BasicDataSource ds = new BasicDataSource();
static {
ds.setUrl("jdbc:h2:mem:test");
ds.setUsername("user");
ds.setPassword("password");
ds.setMinIdle(5);
ds.setMaxIdle(10);
ds.setMaxOpenPreparedStatements(100);
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
private DBCPDataSource(){ }
}
พูลยอดนิยมอันดับสองคือC3PO ชื่อแปลกฉันเห็นด้วย ชื่อ C3PO อ้างอิงถึงหุ่นยนต์ c3po จาก Star Wars และ CP ก็ย่อมาจาก Connection Pool
public class C3p0DataSource {
private static ComboPooledDataSource cpds = new ComboPooledDataSource();
static {
try {
cpds.setDriverClass("org.h2.Driver");
cpds.setJdbcUrl("jdbc:h2:mem:test");
cpds.setUser("user");
cpds.setPassword("password");
} catch (PropertyVetoException e) {
// handle the exception
}
}
public static Connection getConnection() throws SQLException {
return cpds.getConnection();
}
private C3p0DataSource(){}
}
เอกสารประกอบสามารถพบได้ในหน้าทางการ .
และสุดท้าย Connection Pool ที่ได้รับความนิยมสูงสุดในยุคของเราคือHikariCP :
public class HikariCPDataSource {
private static HikariConfig config = new HikariConfig();
private static HikariDataSource ds;
static {
config.setJdbcUrl("jdbc:h2:mem:test");
config.setUsername("user");
config.setPassword("password");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ds = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
private HikariCPDataSource(){}
}
นี่คือ หน้าGitHub อย่างเป็น ทางการ ของเขา
และบทความที่ดีเกี่ยวกับการกำหนดค่า
GO TO FULL VERSION