Kiến trúc JDBC Trong JDBC có 2 loại class chính để tạo kết nối đến một cơ sở dữ liệu: Driver Manager và JDBC Driver, được cung cấp trong 2 package java.sql và javax.sql.. Các đối tượng t
Trang 1JDBC
JDBC 1
1 Giới thiệu JDBC 1
2 Kiến trúc JDBC 1
3 DriverManager 2
4 Connection 5
5 Statement 6
6 ResultSet 8
7 Java và Oracle – OJDBC 9
1 Giới thiệu JDBC
JDBC là chữ viết tắt của "Java DataBase Connectivity", là một chuẩn truy xuất cơ sở dữ liệu trên môi trường Java do Sun MicroSystem đề xuất và phát triển
Thực chất, JDBC là một API (Application Programming Interface) bao gồm các class, interface và exception theo cùng một đặc tả mà từ đó, các công ty sản xuất JDBC driver cũng như các nhà phát triển JDBC đều phải tuân thủ khi phát triển ứng dụng
2 Kiến trúc JDBC
Trong JDBC có 2 loại class chính để tạo kết nối đến một cơ sở dữ liệu: Driver Manager
và JDBC Driver, được cung cấp trong 2 package java.sql và javax.sql
2.1 Driver Manager
Là một class thực sự do JDBC API cung cấp Driver Manager chịu trách nhiệm quản lý các driver đã đăng ký, mà thực chất là là trừu tượng hóa các chi tiết về việc sử dụng một driver, cho nên lập trình viên không cần phải làm việc trực tiếp với driver đó
2.2 JDBC Drivers
Các class này này được cung cấp bởi các nhà sản xuất phần mềm độc lập Các class JDBC Driver có chức năng tạo ra kết nối tới một cơ sở dữ liệu và xử lý tất cả các thao tác giao tiếp với cơ sở dữ liệu đó
2.3 Package java.sql
Dưới đây là các class và interface chính của package java.sql
a Class DriverManager
Có chức năng nạp các JDBC Driver vào bộ nhớ Có thể sử dụng nó để mở các kết nối tới một nguồn dữ liệu
b Interface Connection
Biểu thị một kết nối đến một nguồn dữ liệu Được dùng để tạo ra các đối tượng Statement, PreparedStatement và CallableStatement
Trang 2c Interface Statement
Chứa một câu lệnh SQL tĩnh, kết quả thực thi nó sẽ là một ResultSet
d Interface PreparedStatement
Chứa một câu lệnh SQL đã được dịch, dùng để tăng tốc độ khi cần thực thi nhiều lần cùng một câu lệnh SQL
e Interface CallableStatement
Dùng để biểu diễn các thủ tục SQL Chỉ dùng được với hệ quản trị cơ sở dữ liệu có hỗ trợ thủ tục (như Oracle)
f Interface ResultSet
Dùng để chứa kết quả trả về khi truy vấn dữ liệu
g Exception SQLException
Được phát sinh khi có lỗi xảy ra trong quá trình truy cập cơ sở dữ liệu
2.4 Package javax.sql
Được bổ sung từ phiên bản JDK 1.4, còn có tên là JDBC 2.0 Standard Extension API, package này bổ sung các chứng năng mới vào JDBC để hỗ trợ cho các chức năng đã có trong package java.sql
Dưới đây là các class và interface chính của package javax.sql
a Interface DataSource
Mô tả một nguồn dữ liệu Các đối tượng thuộc interface này có thể được dùng thay cho DriverManager để tạo ra các kết nối tới cơ sở dữ liệu
b Interface XADataSource và XAConnection
Cung cấp khả năng truy cập tới cơ sở dữ liệu được lưu trữ trên nhiều server chỉ trong một transaction
c Interface RowSet
Là sự cải tiến của interface ResultSet (implement từ ResultSet), cung cấp khả năng hỗ trợ JavaBeans Một RowSet có thể được dùng như một thành phần JavaBeans trong môi trường Bean, có thể được tạo ra lúc lập trình và sử dụng lúc chạy ứng dụng
3 DriverManager
3.1 Giới thiệu
Chức năng chính: nạp các JDBC Driver vào bộ nhớ, mở kết nối tới nguồn dữ liệu
Class DriverManager thuộc lớp quản lý của JDBC, hoạt động ở giữangười dùng và các driver Nó quản lý các driver đang có, điều khiển sự thiết lập kết nối giữa cơ sở dữ liệu và driver Thêm vào đó, DriverManager còn có một số chức năng khác như giới hạn thời gian login của driver, xuất ra các file log và theo dõi các thông điệp
Trang 3Từ JDBC 2.0 (javax.sql), DriverManager được nâng cấp thành DataSource với một số chức năng bổ sung như cho phép một transaction truy cập các cơ sở dữ liệu trên các server riêng biệt, cơ chế pooling, hỗ trợ môi trường Bean
3.2 Các phương thức chính
Tất cả các phương thức của DriverManager đều là tĩnh (static) nên ta không cần tạo ra đối tượng DriverManager Do đó, DriverManager cũng không có constructor
void deregisterDriver(Driver driver) Xóa bỏ một driver khỏi danh sách của
DriverManager Connection getConnection(String url) Tạo một kết nối tới cơ sở dữ liệu
Connection getConnection(String url,
String user, String password)
Tạo một kết nối tới nguồn dữ liệu, username và password đăng nhập được tách khỏi URL
Driver getDriver(String url) Trả về một driver đã đăng ký
Enumeration<Driver> getDrivers() Trả về một Enumerator chứa tất cả driver
đã đăng ký
int getLoginTimeout() Trả về thời gian tối đa mà driver có thể chờ
khi cố gắng kết nối tới cơ sở dữ liệu
PrintWriter getLogWriter() Trả về đối tượng đảm nhận việc ghi log của
DriverManager và các driver
void println(String message) In một thông điệp vào log stream hiện hành
void registerDriver(Driver driver) Đăng ký một driver mới
void setLoginTimeout(int seconds) Thiết lập thời gian tối đa mà driver có thể
chờ khi cố gắng kết nối tới cơ sở dữ liệu
void setLogWriter(PrintWriter out) Thiết đặt đối tượng đảm nhận việc ghi log
của DriverManager và các driver
3.3 Cách sử dụng
Trong các ứng dụng đơn giản, thông thường ta chỉ cần dùng phương thức getConnection() của DriverManager Phương thức này dùng để tạo ra một kết nối tới
cơ sở dữ liệu Ngoài ra, ta có thể dùng các phương thức registerDriver() để đang ký một driver mới, getDriver() để lấy thông tin về một driver đã có,
Trang 43.3.1 Đăng ký một JDBC Driver
Một JDBC Driver thực chất là một class do nhà sản xuất phần mềm cung cấp để kết nối tới một cơ sở dữ liệu cụ thể nào đó Class này phải tuân theo những quy định của JDBC
do Sun đặt ra Để dùng một driver chưa có trong DriverManager thì ta phải đăng ký nó
Để đăng ký một JDBC Driver ta có ba cách:
Đăng ký nó như là một class bình thường bằng phương thức tĩnh Class.forName()
// Nạp và đăng ký lớp HocSinh trong package hocsinh
// sau đó trả về một đối tượng Class kiểu HocSinh
Class.forName( "hocsinh.HocSinh" );
Đăng ký nó như là một JDBC Driver bằng phương thức tĩnh DriverManager.registerDriver()
// Đăng ký lớp myDriver trong package myjdbc
DriverManager.registerDriver(new mykdbc.myDriver());
Đăng ký nó với thuộc tính jdbc.drivers của lớp java.lang.System Khi chạy chương trình, DriverManager sẽ tự nạp các driver trong thuộc tính này
Thông thường, ta dùng hai cách đầu tiên vì chúng an toàn hơn
3.3.2 Tạo kết nối tới cơ sở dữ liệu
Sau khi đã nạp và đăng ký JDBC Driver, ta có thể tạo kết nối tới cơ sở dữ liệu bằng phương thức DriverManager.getConnection()
Khi phương thức getConnection() được gọi, DriverManager sẽ kiểm tra lần lượt các driver đã đăng ký xem driver nào có thể tạo kết nối tới cơ sở dữ liệu được mô tả trong chuỗi đầu vào của phương thức
Nếu được thực thi thành công, kết quả trả về của phương thức getConnection() sẽ là một đối tượng thuộc interface Connection
Connection cn = DriverManager.getConnection( "url" , "usrname" , "passwd" ); Đôi khi với cùng một cơ sở dũ liệu, ta có nhiều driver thích hợp để tạo kết nối Khi đó thì thứ tự driver là quan trọng, vì DriverManager sẽ lấy driver phù hợp đầu tiên mà nó tìm thấy trong danh sách driver để sử dụng
Cơ chế hoạt động của việc tạo kết nối như sau:
Để tìm driver phù hợp, DriverManager sẽ dùng thử các driver đã biết theo thứ tự đăng ký theo nguyên tắc driver đăng ký trước sẽ được thử trước các driver lưu trong thuộc tính jdbc.drivers sẽ được thử đầu tiên DriverManager sẽ không dùng các driver chứa những đoạn mã mà nó xem là đáng tin cậy, trừ khi driver đó được nạp trong cùng đoạn mã chương trình với câu lệnh tạo kết nối
Với mỗi driver trong danh sách, DriverManager sẽ kiểm tra bằng cách gọi phương thức Driver.connect() Driver đầu tiên nhận diện được đoạn URL trong phương thức getConnection() sẽ được sử dụng
Trang 54 Connection
4.1 Giới thiệu
Một đối tượng Connection là một kết nối (hoặc một phiên làm việc) tới một cơ sở dữ liệu cụ thể nào đó Đối tượng Connection dùng để gởi câu lệnh SQL tới cơ sở dữ liệu và nhận kết quả thực thi câu lệnh SQL đó từ cơ sở dữ liệu
Mặc định, các đối tượng Connection sẽ hoạt động ở chế độ tự động commit, có nghĩa là các câu lệnh SQL sẽ được commit tự động sau khi thực thi xong Nếu không dùng chế độ
tự động commit, ta phải tự gọi phương thức commit() để bảo đảm việc thay đổi trên cơ
sở dữ liệu là có hiệu lực
Từ JBDC 2.1, mỗi đối tượng Connection sẽ có một đối tượng Map (java.util.Map) bên trong để ánh xạ các kiểu dữ liệu của cơ sở dữ liệu thành các class của Java Chi tiết xin xem trong Java API Documents
4.2 Các phương thức chính
void clearWarnings() Đóng một kết nối tới cơ sở dữ liệu và giải
phóng các tài nguyên ứng với kết nối đó
void commit()
Ghi thẳng những thay đổi xuống cơ sở dữ liệu (với hệ quản trị cơ sở dữ liệu dùng cơ chế commit / rollback như Oracle)
Statement createStatement() Tạo ra đối tượng Statement để chứa câu
lệnh SQL
Statement createStatement(int
resultSetType, int
resultSetConcurrency)
Tạo ra đối tượng Statement, và Statement này sẽ sinh ra các đối tượng ResultSet theo quy định trong các tham số
boolean getAutoCommit() Trả về chế độ tự động commit
boolean isClosed() Cho biết Connection được đóng hay chưa
boolean isReadOnly() Cho biết Connection có thuộc dạng
read-only (chỉ cho phép truy vấn) hay không CallableStatement prepareCall(String
sql)
Tạo ra đối tượng CallableStatament để chứa thủ tục SQL lưu trong tham số sql
PreparedStatement
prepareStatement(String sql)
Tạo ra đối tượng PreparedStatament để chứa câu lệnh SQL lưu trong tham số sql
void rollback() Hủy bỏ những thay đổi của câu lệnh SQL
void rollback(Savepoint savepoint) Quay lại một mốc phục hồi đã tạo từ trước
Trang 6void setAutoCommit(boolean
autoCommit) Thiết đặt bật/tắt chế độ tự động commit
void setReadOnly(boolean readOnly) Thiết đặt bật/tắt chế độ read-only (chỉ cho
phép truy vấn) Savepoint setSavepoint(String name) Thiết đặt một cột mốc phục hồi
4.3 Cách sử dụng
Sau khi đã tạo ra đối tượng Connection từ DriverManager (bằng phương thức DriverManager.getConnection() đã nói ở trên) Khi đã có đối tượng Connection, ta dùng nó để tạo ra các đối tượng Statament lưu các câu lệnh SQL
Phương thức thường dùng: createStatement(int resultSetType, int
resultSetConcurrency)
Statement sm = cn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
5 Statement
5.1 Giới thiệu
Interface Statement đưa ra các quy định cơ bản mà class Statement (do các nhà sản xuất phần mềm cung cấp) phải tuân theo
Các đối tượng Statement được dùng để gởi một câu lệnh SQL tĩnh tới hệ quản trị cơ sở
dữ liệu Có 3 loại Statement là Statement, PreparedStatement (kế thừa từ Statement) và CallableStatement (kế thừa từ PreparedStatement) Chức năng cụ thể của từng loại Statement như sau:
Đối tượng Statement được dùng để thực thi một câu SQL đơn giản, không có tham số
Đối tượng PreparedStatement được dùng để thực thu một câu lệnh SQL đã được dịch, có thể có tham số dạng IN
Đối tượng CallableStatement được dùng để thực thi một thủ tục SQL trong cơ
sở dữ liệu (chỉ dùng được với hệ quản trị cơ sở dữ liệu có hỗ trợ việc tạo và thực thi thủ tục – như Oracle)
5.2 Các phương thức chính
void addBatch(String sql)
Thêm một câu lệnh SQL vào danh sách lệnh của Statement, dùng khi cần chạy nhiều câu lệnh SQL
void cancel() Hủy bỏ câu lệnh SQL, chỉ dùng được với hệ
Trang 7quản trị có hỗ trợ chức năng này
void clearBatch() Xóa danh sách lệnh của Statement
void close() Đóng đối tượng Statement
boolean execute(String sql)
Thực thi câu lệnh SQL, có thể trả về nhiều kết quả dùng getResultSet(), getUpdateCount() và getMoreResults()
để lấy lần lượt các kết quả
int[] executeBatch() Thực thi một danh sách lệnh SQL
ResultSet executeQuery(String sql) Thực thi câu truy vấn và trả về kết quả trong
ResultSet
int executeUpdate(String sql) Thực thi câu lệnh có thay đổi dữ liệu (insert,
update, delete)
boolean getMoreResults() Dịch chuyển tới kết quả kế tiếp, trả về true
nếu kết quả là một ResultSet
ResultSet getResultSet() Lấy kết quả lưu trong ResultSet của câu
lệnh SQL Ngoài ra còn rất nhiều phương thức khác, chi tiết xin xem trong Java API Documents
5.3 Cách sử dụng
5.3.1 Tạo câu lệnh
Khi tạo xong kết nối tới cơ sở dữ liệu, ta sẽ dùng kết nối đó để gởi các câu lệnh SQL Đối tượng Statement được dùng để lưu câu lệnh SQL cần thực thi, được tạo ra từ phương thức createStatement() của đối tượng Connection
Statement stmt = con.createStatement();
5.3.2 Thực thi câu lệnh
Thực thi câu lệnh với đối tượng Statement: bằng các phương thức execute(), executeBatch(), executeQuery() và executeUpdate()
ResultSet rs = sm.executeQuery ("select * from jobs" );
5.3.3 Hoàn tất câu lệnh
Khi chạy xong câu lệnh có thay đổi dữ liệu (executeUpdate()), nếu không bật chế độ tự động commit thì ta phải gọi commit để ghi thẳng các thay đổi xuống cơ sở dữ liệu
Một số hệ quản trị cơ sở dữ liệu xem thủ thục như là một tập hợp các lệnh riêng biệt, một
số hệ khác thì xem thủ tục là một câu lệnh phức Do đó cần lưu ý chế độ tự động commit khi chạy thủ tục vì nó ảnh hưởng tới lời gọi phương thức commit() Trong trường hợp
Trang 8đầu tiên, từng câu lệnh sẽ được commit riêng biệt, trong trường hợp sau, các câu lệnh sẽ được commit cùng lúc
5.3.4 Đóng đối tượng Statement
Đối tượng Statement sẽ được garbage collection đóng, tuy nhiên ta nên đóng nó khi không cần dùng nữa để giải phóng tài nguyên càng sớm càng tốt, và giúp chương trình an toàn hơn bằng phương thức close()
sm.close();
6 ResultSet
6.1 Giới thiệu
Trong Java, ResultSet là đối tượng chứa kết quả thực thi một câu truy vấn SQL Nói cách khác, nó chứa các dòng thỏa điều kiện truy vấn Thông thường, dữ liệu lưu trong ResultSet được lấy ra bằng các phương thức getXXX() và next()
Thực chất, ResultSet sẽ nắm giữ một cursor chỉ tới các dòng của tập dữ liệu truy vấn được Ban đầu, cursor chỉ tới vị trí liền trước dòng đầu tiên của kết quả truy vấn Sau mỗi lời gọi next(), cursor sẽ dịch chuyển sang dòng tiếp theo lần gọi next() đầu tiên sẽ làm cho cursor chỉ tới dòng đầu tiên
Nếu driver được implement từ JDBC 1.0 API, ResultSet sẽ chỉ có thể di chuyển về trước nên sẽ thuộc loại ResultSet.TYPE_FORWARD_ONLY
Nếu driver được implement từ JDBC 2.0 API, ResultSet sẽ có khả năng "cuộn", có nghĩa là nó cho phép dịch chuyển hai chiều
6.2 Cách sử dụng
Tạo đối tượng ResultSet từ việc thực thi câu truy vấn trong đối tượng Statement:
ResultSet rs=sm.executeQuery( "select * from jobs" );
Chuyển đến dòng đầu tiên bằng phương thức next():
rs.next();
Những lần gọi phương thức next() sau đó sẽ chuyển đến dòng kế tiếp, và phương thức này sẽ trả về false nếu hết dòng
Lấy dữ liệu: mỗi dòng có nhiều cột, để lấy dữ liệu từ một dòng ta sẽ lấy lần lượt dữ liệu trong các cột của dòng đó bằng phương thức getXXX() (với XXX là kiểu dữ liệu) Khi lấy
dữ liệu từ cột, ta truyền vào tham số là tên cột hoặc số thứ tự của cột
System.out.println(rs.getString( "JOB_ID" ));
Có rất nhiều phương thức getXXX() như getString(), getFloat(), getInt(), chi tiết xin xem trong Java API Documents
Trang 96.3 Các ví dụ
6.3.1 Ví dụ cơ bản
Giả sử ta có bảng Table1 với 3 cột a, b, c Khi thực thi cấu truy vấn "SELECT a, b, c FROM Table1", dữ liệu truy vấn được sẽ như sau:
a b c
- - -
12345 Cupertino 2459723.495
83472 Redmond 1.0
83492 Boston 35069473.43
Đoạn mã sau sẽ lấy kết quả trong ResultSet và đưa ra màn hình:
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery( "SELECT a, b, c FROM Table1" );
while (rs.next())
{
// Lấy và in giá trị của dòng hiện hành
int i = rs.getInt( "a" );
String s = rs.getString( "b" );
float f = rs.getFloat( "c" );
System.out.println( "ROW = " + i + "\t" + s + "\t" + f);
}
6.3.2 Ví dụ về sự dịch chuyển cursor
Đoạn mã sau sẽ minh họa cách dịch chuyển cursor của ResultSet tên là rs theo thứ tự
từ đầu tới cuối:
rs.beforeFirst(); // Đưa cursor về vị trí trước dòng đầu
while (rs.next()) // Dịch chuyển tới dòng kế, trả về false nếu hết dòng
{
System.out.print (rs.getString( "EMP_NO" ) + "\t" );
System.out.println(rs.getFloat( "SALARY" );
}
Đoạn mã sau sẽ minh họa cách dịch chuyển cursor của ResultSet tên là rs theo thứ tự
từ cuối lên đầu:
rs.afterLast(); // Đưa cursor về vị trí sau dòng cuối
while (rs.previous()) // Chuyển tới dòng trước, trả về false nếu hết
{
System.out.print (rs.getString( "EMP_NO" ) + "\t" );
System.out.println(rs.getFloat( "SALARY" );
}
7 Java và Oracle – OJDBC
Trong phần trước ta đã điểm qua các chứng năng tổng quát của JDBC, phần này sẽ trình bày cụ thề về cách dùng JDBC với hệ quản trị CSDL Oracle
Trang 107.1 Bổ sung các thư viện mô tả các class của OJBDC
Ta phải thêm các tập tin chứa các lớp thư viện JDBC do Oracle cung cấp, các lớp này nằm trong hai tập tin là ojdbc14dms.jar và dms.jar
Trươc hết, copy các file .jar như trên về máy mình
7.1.1 Dùng JCreator
Vào menu "Project" "Project Properties " Trong hộp thoại vừa mở ra, chọn thẻ
"Required Libraries"
Nhấn nút "New ", chọn "Add" "Add Archive "