Apache Derby Bài 24: Quản lý Network Server thông qua API Java (NetworkServerControl)
1. Tại sao cần quản lý Network Server bằng mã Java?
Trong các bài trước, chúng ta đã khởi động và dừng Derby Network Server bằng các lệnh CLI như startNetworkServer và stopNetworkServer. Tuy nhiên, trong nhiều kịch bản thực tế, việc dựa vào người dùng mở Terminal gõ lệnh là không khả thi:
-
Tự động hóa kiểm thử (Integration Testing): Bạn muốn hệ thống tự động dựng một máy chủ CSDL lên trước khi chạy bộ test, và tự động tắt nó đi khi test xong.
-
Ứng dụng lai (Hybrid App): Ứng dụng Desktop hoặc Web Backend của bạn vừa muốn tự lưu trữ dữ liệu cục bộ (như Embedded Mode), nhưng đồng thời cũng muốn mở cổng để các công cụ bên ngoài kết nối vào giám sát.
-
Quản trị tập trung: Bạn muốn viết một bảng điều khiển (Dashboard) trên nền Web để quản trị viên có nút bấm Khởi động/Dừng máy chủ CSDL.
Apache Derby cung cấp lớp org.apache.derby.drda.NetworkServerControl để giúp bạn kiểm soát hoàn toàn vòng đời của máy chủ mạng ngay bên trong mã nguồn Java.
2. Cấu hình thư viện Maven/Gradle
Để ứng dụng Java của bạn có quyền khởi tạo máy chủ mạng, bạn cần bổ sung thêm thư viện derbynet vào dự án (bên cạnh thư viện lõi derby).
Nếu dùng Maven, hãy thêm vào tệp pom.xml:
XML
<dependencies>
<!-- Thư viện lõi Engine -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.17.1.0</version>
</dependency>
<!-- Thư viện điều khiển Network Server -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
<version>10.17.1.0</version>
</dependency>
</dependencies>
3. Các phương thức cốt lõi của NetworkServerControl
Lớp NetworkServerControl cung cấp các hàm API tương ứng 1-1 với các lệnh CLI mà bạn đã biết:
1. Khởi tạo đối tượng
Bạn truyền vào địa chỉ IP (tương đương cờ -h) và cổng mạng (tương đương cờ -p):
Java
InetAddress address = InetAddress.getByName("localhost");
NetworkServerControl serverControl = new NetworkServerControl(address, 1527);
2. Khởi động máy chủ (start)
Khởi động máy chủ và chuyển hướng log xuất ra một PrintWriter (thường là màn hình Console hoặc một tệp nhật ký tùy chỉnh):
Java
serverControl.start(new PrintWriter(System.out, true));
Lưu ý: Phương thức start() sẽ sinh ra luồng (thread) chạy ngầm và trả về quyền điều khiển ngay lập tức cho Java. Tuy nhiên, lúc này máy chủ có thể chưa khởi động xong hoàn toàn.
3. Kiểm tra trạng thái (ping)
Vì start() không chặn (non-blocking) luồng chính, bạn phải dùng hàm ping() để kiểm tra xem máy chủ đã sẵn sàng nhận kết nối hay chưa trước khi thực thi SQL:
Java
serverControl.ping();
Hàm này sẽ ném ra Exception nếu máy chủ chưa mở cửa. Ta thường đưa nó vào một vòng lặp while kết hợp Thread.sleep().
4. Tắt máy chủ (shutdown)
Gửi lệnh đóng băng các kết nối mới và tắt an toàn máy chủ Derby:
Java
serverControl.shutdown();
4. Thực hành: Xây dựng Class điều khiển máy chủ tự động
Đoạn mã dưới đây minh họa một quy trình hoàn chỉnh: Khởi động Server trên cổng 1527 Chờ đến khi Server sẵn sàng Kết nối vào Server qua giao thức mạng Dừng Server an toàn.
Java
package com.hieu.derby.server;
import org.apache.derby.drda.NetworkServerControl;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.sql.Connection;
import java.sql.DriverManager;
public class EmbeddedNetworkServerDemo {
public static void main(String[] args) {
NetworkServerControl server = null;
try {
System.out.println("1. Chuẩn bị khởi động Derby Network Server...");
// Lắng nghe trên localhost, cổng 1527
InetAddress address = InetAddress.getByName("localhost");
server = new NetworkServerControl(address, 1527);
// Khởi động server và in log trực tiếp ra System.out
server.start(new PrintWriter(System.out, true));
// Vòng lặp chờ Server sẵn sàng (Ping tối đa 10 lần)
boolean isServerUp = false;
for (int i = 0; i < 10; i++) {
try {
server.ping();
isServerUp = true;
break; // Ping thành công, thoát vòng lặp
} catch (Exception e) {
System.out.println(" -> Đang chờ server khởi động...");
Thread.sleep(500); // Đợi nửa giây rồi ping lại
}
}
if (!isServerUp) {
System.err.println("Lỗi: Không thể khởi động máy chủ!");
return;
}
System.out.println("\n2. Máy chủ đã sẵn sàng! Ứng dụng tiến hành kết nối...");
// Lưu ý: Mặc dù khởi động chung JVM, ta vẫn phải kết nối qua jdbc:derby://
String jdbcUrl = "jdbc:derby://localhost:1527/demo_api_db;create=true";
// Nạp driver Client và kết nối
try (Connection conn = DriverManager.getConnection(jdbcUrl)) {
System.out.println("=> Đã kết nối TCP/IP tới DB thành công!");
// (Thực thi các lệnh SQL tại đây...)
System.out.println("=> Hoàn tất công việc, chuẩn bị ngắt kết nối.");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Đảm bảo Server luôn được tắt khi ứng dụng kết thúc
if (server != null) {
try {
System.out.println("\n3. Đang gửi lệnh tắt Network Server...");
server.shutdown();
System.out.println("=> Server đã tắt an toàn.");
} catch (Exception e) {
System.err.println("Lỗi khi tắt Server: " + e.getMessage());
}
}
}
}
}
Phân tích điểm nổi bật:
Sự kết hợp này tạo ra mô hình "Máy chủ nhúng giả lập mạng". Máy chủ chạy nội bộ bên trong ứng dụng Java, nhưng bản thân nó lại mở cổng 1527. Nhờ đó, trong lúc ứng dụng Java đang chạy, bạn hoàn toàn có thể mở DBeaver hoặc DataGrip ở bên ngoài kết nối thẳng vào database để xem dữ liệu theo thời gian thực (điều không thể làm được ở Embedded Mode thuần túy).
5. Tổng kết
-
Lớp
NetworkServerControl(thuộc thư việnderbynet.jar) là cầu nối để quản lý máy chủ Derby bằng mã nguồn Java. -
Luôn sử dụng vòng lặp
ping()sau lệnhstart()để đảm bảo luồng thực thi chỉ tiếp tục khi máy chủ đã mở cổng TCP thành công. -
Việc tích hợp
NetworkServerControlmang lại sự linh hoạt tuyệt đối: vừa tự động hóa vòng đời của CSDL như Embedded Mode, vừa cho phép các tiến trình bên ngoài kết nối giám sát như Network Server Mode.
Giờ đây khi máy chủ Derby đã có thể lắng nghe ở cổng mạng (1527), việc quan sát và tương tác với dữ liệu không còn bị bó hẹp trong các công cụ CLI tối nghĩa. Bài tiếp theo sẽ hướng dẫn cách sử dụng các giao diện đồ họa chuyên nghiệp: Apache Derby Bài 25: Kết nối Apache Derby bằng các công cụ GUI: DBeaver, DataGrip, IntelliJ IDEA.
All rights reserved