Lập trình mạng với Java - Chương 9: Xử lý cơ sở dữ liệu trong Java
Các ứng dụng Internet ngày nay thường được dựa trên các cơsởdữliệu lớn được
cài đặt bằng cách sửdụng công nghệcơsởdữliệu quan hệ. Kểtừkhi xuất hiện từnăm
1995, Java được yêu cầu cần cung cấp khảnăng kết nối với các cơsởdữliệu quan hệ
hiện có nhưIngres, Oracle, Access, và SQL Server, Các tiện ích cho phép truy xuất cơ
sởdữliệu nằm trong gói java.sql.
Ngày nay các thông tin với dung lượng lớn đều được lưu trữtrong các kho dữliệu
lớn. Khảnăng truy xuất tới các cơsởdữliệu là điều không thểthiếu đối với các ứng
dụng. Điều này lại càng đúng với các ứng dụng chạy trên mạng máy tính nói chung và
Internet nói riêng. Trong chương này chúng ta sẽ đi vào tìm hiểu giao diện lập trình ứng
dụng JDBC của Java và cách thức đểkết nối với một cơsởdữliệu từmột ứng dụng Java
thông qua JDBC.
ObjectOuputStream:
ObjectOuputStream oos=new ObjectOutputStream(os);
Việc truyền đối tượng lúc này trở thành một công việc rất đơn giản:
oos.writeObject(obj);
oos.flush();
2.4. Ví dụ minh họa
Để minh họa kỹ thuật chúng ta viết một server thực hiện phép nhân
hai mảng số nguyên với nhau. Client gửi hai đối tượng, mỗi đối tượng biểu
diễn một mảng nguyên; server nhận các đối tượng này, thực hiện lời gọi
phương nhân hai mảng số nguyên với nhau và gửi kết quả trả về cho client.
Trước tiên chúng ta định nghĩa đối tượng để có thể sử dụng trong
việc truyền các đối tượng.
public class ArrayObject implements java.io.Serializable{
private int[] a=null;
public ArrayObject(){
}
public void setArray(int a[]){
this.a=a;
}
public int[] getArray(){
return a;
}
}
Lớp ArrayObject là lớp được xây dựng để đóng gói các mảng số
nguyên và có khả năng truyền đi qua lại trên mạng. Cấu trúc lớp như sau:
trường thông tin là một mảng số nguyên a[]; phương thức setArray() thiết
lập giá trị cho mảng. Phương thức getArray() trả về một mảng số nguyên từ
đối tượng ArrayObject.
Mô hình client/server tối thiểu phải có hai mođun client và server.
Trong ví dụ này cũng vậy ta sẽ xây dựng một số mođun chương trình như
sau:
Đầu tiên chúng ta phát triển client. Client tạo ra hai thể hiện của các
đối tượng ArrayObject và ghi chúng ra luồng xuất (thực chất là gửi tới
server).
public class ArrayClient{
public static void main(String[] args)throws Exception{
ObjectOuputStream oos=null;
ObjectInputStream ois=null;
int dat1[]={3,3,3,3,3,3,3};
int dat2[]={5,5,5,5,5,5,5};
Socket s=new Socket("localhost",1234);
oos=new ObjectOuputStream(s.getObjectOuput());
ois=new ObjectInputStream(s.getInputStream());
ArrayObject a1=new ArrayObject();
a1.setArray(dat1);
ArrayObject a2=new ArrayObject();
a2.setArray(dat2);
ArrayObject res=null;
int r[]=new int[7];
oos.writeObject(a1);
oos.writeObject(a2);
oos.flush();
res=(ArrayObject)ois.readObject();
r=res.getArray();
System.out.println("The result received from server...");
System.out.println();
for(int i=0;i<r.length;i++)System.out.print(r[i]+" ");
}
}
Bước tiếp theo chúng ta phát triển server. Server là một chương trình
cung cấp dịch vụ phục vụ các yêu cầu của client. Server nhận hai đối tượng
ArrayObject và nhận về hai mảng từ hai đối tượng này và sau đó đem nhân
chúng với nhau và gửi kết quả trở lại cho client.
public class ArrayServer extends Thread {
private ServerSocket ss;
public static void main(String args[])throws Exception
{
new ArrayServer();
}
public ArrayServer()throws Exception{
ss=new ServerSocket(1234);
System.out.println("Server running on port "+1234);
this.start();
}
public void run(){
while(true){
try{
System.out.println("Waiting for client...");
Socket s=ss.accept();
System.out.println("Accepting a connection
from:"+s.getInetAddress());
Connect c=new Connect(s);
}
catch(Exception e){
System.out.println(e);
}
}
}
}
Trong mô hình client/server tại một thời điểm server có thể phục vụ
các yêu cầu đến từ nhiều client, điều này có thể dẫn đến các vấn đề tương
tranh. Chính vì lý do này mà lớp ArrayServer thừa kế lớp Thread để giải
quyết vấn đề trên. Ngoài ra để nâng cao hiệu suất của chương trình thì sau
khi đã chấp nhận liên kết từ một client nào đó, việc xử lý dữ liệu sẽ được
dành riêng cho một tuyến đoạn để server có thể tiếp tục chấp nhận các yêu
cầu khác. Hay nói cách khác, mỗi một yêu cầu của client được xử lý trong
một tuyến đoạn riêng biệt.
class Connect extends Thread{
private Socket client=null;
private ObjectInputStream ois;
private ObjectOuputStream oos;
public Connect(){
}
public Connect(Socket client){
this.client=client;
try{
ois=new ObjectInputStream(client.getInputStream());
oos=new ObjectOuputStream(client.getObjectOuput());
}
catch(Exception e){
System.err.println(e);
}
this.start();
}
public void run(){
ArrayObject x=null;
ArrayObject y=null;
int a1[]=new int[7];
int a2[]=new int[7];
int r[]=new int[7];
try{
x=(ArrayObject)ois.readObject();
y=(ArrayObject)ois.readObject();
a1=x.getArray();
a2=y.getArray();
for(int i=0;i<a1.length;i++)r[i]=a1[i]*a2[i];
ArrayObject res=new ArrayObject();
res.setArray(r);
oos.writeObject(res);
oos.flush();
ois.close();
client.close();
}
catch(Exception e){
}
}
}
3. Truyền các đối tượng thông qua giao thức UDP
Một giao thức gần với giao thức TCP là giao thức UDP. Java hỗ trợ
cho kiểu ứng dụng truyền tin phi liên kết trên giao thức UDP thông qua lớp
DatagramSocket và DatagramPacket. Liệu chúng ta có thể viết được các
chương trình nhập và xuất đối tượng bằng truyền tin datagram? Thực hiện
điều này không thể tiến hành trực tiếp như với luồng Socket. Vấn đề là
DatagramSocket không được gắn với bất kỳ luồng nào; mà nó sử dụng một
tham số mảng byte để gửi và nhận dữ liệu.
Hình 6
Có thể thấy rằng để xây dựng một gói tin datagram, đối tượng phải
được chuyển thành một mảng byte. Việc chuyển đổi này rất khó để thực
hiện nếu bản thân đối tượng có liên quan đến một số đối tượng phức tạp
trong đồ thị đối tượng.
Hình 6 minh họa dòng luân chuyển dữ liệu khi truyền một đối tượng
thông qua một datagram. Dưới đây là bảy bước ta cần thực hiện để cài đặt
mô hình truyền dữ liệu cho giao thức UDP
• Bước 1. Chuẩn bị: Tạo đối tượng cần truyền đi, giả sử đối tượng này
là obj, làm cho nó khả tuần tự bằng cách thực thi giao tiếp
Serializable.
• Bước 2. Tạo một luồng ByteArrayObjectOuput và đặt tên cho nó là
baos.
• Bước 3. Xây dựng đối tượng ObjectOuputStream và đặt tên cho nó là
oos. Tham số cho cấu tử ObjectOuputStream là baos
• Bước 4. Ghi đối tượng obj vào luồng baos bằng cách sử dụng
phương thức writeObject() của oos.
• Bước 5. Tìm kiếm vùng đệm dữ liệu mảng byte từ bằng cách sử dụng
phương thức toByteAray().
Object
ObjectOuputStream
ByteArrayObjectOuput
DatagramPacket
Object
ObjectInputStream
ByteArrayInputStream
DatagramPacket
Network
• Bước 6. Xây dựng đối tượng DatagramPacket và đặt tên là dp với dữ
liệu đầu vào là vùng đệm dữ liệu đã tìm được ở bước 5.
• Bước 7. Gửi dp thông qua DatagramSocket bằng cách gọi phương
thức send() của nó.
Ví dụ minh họa chi tiết quá trình gửi một đối tượng
InetAddress ia=InetAddress.getByName("localhost");
Student st=new Student("Peter",7,8,9);
DatagramSocket ds=new DatagramSocket();
ByteArrayObjectOuput baos=new ByteArrayObjectOuput(5000);
ObjectOuputStream oos=new ObjectOuputStream(new
BufferedObjectOuput(baos));
oos.flush();
oos.writeObject(st);
oos.flush();
byte[] b=baos.toByteAray();
DatagramPacket dp=new DatagramPacket(b,b.length,ia,1234);
ds.send(dp);
oos.close();
Để nhận một đối tượng ta cũng tiến hành các bước như trên nhưng theo
thứ tự ngược lại, thay thế luồng ObjectOuputStream bằng
ObjectInputStream và ByteArrayObjectOuput bằng ByteArrayInputStream.
Ví dụ dưới đây minh họa chi tiết quá trình nhận một đối tượng
DatagramSocket ds=new DatagramSocket(1234);
while(true){
byte b[]=new byte[5000];
DatagramPacket dp=new DatagramPacket(b,b.length);
ds.receive(dp);
ByteArrayInputStream bais=new
ByteArrayInputStream(new BufferedInputStream(b));
ObjectInputStream ois =new ObjectInputStream(bais);
Student st=(Student)ois.readObject();
st.computeAverage();
st.print();
ois.close();
bais.close();
}
4. Kết luận
Qua bài báo này tôi đã giới thiệu tổng quan về tuần tự hóa đối tượng.
Thông qua các ví dụ chúng ta thấy không quá khó để làm việc với tuần tự
hóa đối tượng và điều quan trọng hơn là chúng ta đã biết cách để truyền đi
các đối tượng có cấu trúc phức tạp thông qua các Socket.
Ngoài ra, bài báo cũng đã đề cập tới cách truyền đối tượng bằng
cách sử dụng các gói tin datagram. Nhờ những ưu điểm của tiện ích tuần tự
hóa đối tượng, tôi đã minh họa một cách truyền các đối tượng bằng cách
sử dụng các gói tin datagram. Như chúng ta đã thấy, mặc dù trong giao
thức này không hỗ trợ xử lý theo luồng dữ liệu nhưng tôi đã “luồng hóa” các
đối tượng để đưa các đối tượng vào các mảng byte.
Sự lựa chọn giữa việc sử dụng RMI hay giải pháp Socket kết hợp với
tuần tự hóa phụ thuộc vào từng dự án và các yêu cầu của nó. Sự lựa chọn
giải pháp nào chính là sự thỏa hiệp giữa các đặc trưng của mỗi giải pháp:
nếu đối với RMI thì đó là tính đơn giản khi triển khai, ngược lại với Socket
kết hợp với tuần tự hóa đối tượng thì đó lại là ưu thế về mặt hiệu năng. Nếu
vấn đề hiệu năng có tầm quan trọng thì giải pháp lập trình Socket kết hợp
tuần tự hóa đối tượng là giải pháp tốt hơn so với RMI.
90
TÀI LIỆU THAM KHẢO
[1] Elliotte Rusty Harold, Java Network Programming
[2] Nguyễn Phương Lan- Hoàng Đức Hải, Java lâp trình mạng, Nhà xuất bản Giáo
dục
[3] Darrel Ince & Adam Freemat, Programming the Internet with Java, Addison-
Wesley
[4] Mary Campione&Kathy Walrath&Alison Huml, Java™ Tutorial, Third Edition: A
Short Course on the Basics, Addison Wesley
[5] The Complete Java 2Reference
[6] Nguyễn Thúc Hải, Mạng máy tính và các hệ thống mở, Nhà xuất bản Giáo dục
[7] Đoàn Văn Ban, Lập trình hướng đối tượng với Java, Nhà xuất bản Khoa học
và Kỹ thuật
Tài liệu tham khảo
[1] Douglas E.Comer, David L.Stevens, Client-Server Programming And
Applications. In book: Internetworking with TCP/IPVolume III, Pearson
Education, Singapore, 2004.
[2] Herbert Schildt, JavaTM 2: The Complete Reference Fifth Edition, Tata
McGraw-Hill Publishing Company Limited, India, 2002.
[3] Elliote Rusty Harold, JavaTM Network Programming, Third Edition,
Oreilly, 2005.
[4] Qusay H. Mahmoud, Advanced Socket Programming,
December 2001
[5] Shengxi Zhou, Transport Java objects over the network with datagram
packets, 2006
File đính kèm:
Lập trình mạng với Java - Chương 9_Xử lý cơ sở dữ liệu trong Java.pdf

