CD1-CNPM - JAVA HIENLTH Chủ đề 4: JDBC (JAVA DATABASE CONNECTIVITY)
CD1-CNPM - JAVA HIENLTH
Nội dung
• Các trình điều khiển JDBC
• Nạp trình điều khiển và kết nối CSDL
• Câu lệnh Statement
• Thực thi Statement
• ResultSet
• Các interface: DatabaseMetadata, ResultsetMetadata
• Transaction
2
CD1-CNPM - JAVA HIENLTH
Khái niệm JDBC
•Là một bộ API cung cấp cho java developer
khả năng kết nối tới CSDL.
•API này ở cấp độ SQL, có nghĩa là JDBC phải
cho phép người lập trình tạo dựng các câu lệnh
SQL và nhúng nó vào bên trong các lời gọi API
CD1-CNPM - JAVA HIENLTH
Kiến trúc JDBC
Java Application
JDBC Driver Manager
JDBC Drivers
Database
JDBC API
JDBC Driver API
CD1-CNPM - JAVA HIENLTH
Kiến trúc JDBC
•Một trong những mục tiêu khi thiết kế JDBC là phải cung cấp cho developer cách thức làm việc như nhau khi làm việc với các hệ quản trị cơ sở dữ liệu khác nhau.
• JDBC cung cấp một tập hợp các interface
• Java developer không cần phải quan tâm đến sự khác nhau khi giao tiếp với các HQTCSDL khác nhau.
CD1-CNPM - JAVA HIENLTH
Kiến trúc JDBC Java Application
JDBC Driver Manager
SQLServer
Driver
MySQL
Driver
Oracle
DriverODBC Bridge
Driver
DB2
Driver
ODBC Bridge
Manager
Access
DriverdBase
Driver
Access dBase SQL Server MySQL Oracle DB2
CD1-CNPM - JAVA HIENLTH
JDBC
Java Application
1. Mở kết nối
2. Gửi SQL
3. Rút trích dữ liệu
4. Đóng kết nối
DBMS
1. Tạo phiên kết nối
2. Thực thi SQL
3. Trả kết quả
4. Đóng phiên kết nối
8
CD1-CNPM - JAVA HIENLTH
JDBC API
• JDBC API (Java Database Connectivity
Aplication Programming Interface): cung
cấp các lớp và interface hỗ trợ các ứng
dụng java tương tác với các hệ quản trị
CSDL.
• Chủ yếu nằm trong gói java.sql. Một vài
lớp và interface có các chức năng nâng
cao nằm trong gói javax.sql
CD1-CNPM - JAVA HIENLTH
Các trình điều khiển JDBC (JDBC Drivers)
• Hiện nay có rất nhiều Hệ quản trị CSDL
(DBMS) khác nhau như SQL Sever,
MySQL, Oracle, MS Access, FoxPro,…
• Để truy cập các DBMS khác nhau từ
chương trình viết bằng Java thì ta cần có
các JDBC driver tương ứng.
• Đảm bảo ứng dụng tương tác với DBMS
theo một cách thức chuẩn thống nhất.
CD1-CNPM - JAVA HIENLTH
Các trình điều khiển JDBC (JDBC Drivers)
• Hãng Sun đã đưa ra 4 loại JDBC driver.
• JDBC-ODBC Bridge.
• Native-API Driver.
• JDBC-Net Driver, Pure Java.
• Native-Protocol Driver, Pure Java.
• Tham khảo thêm tại:
http://industry.java.sun.com/products/jdbc/drivers
CD1-CNPM - JAVA HIENLTH
Cầu nối JDBC - ODBC
• Được cung cấp bởi Sun – jdk
• Có thể truy xuất bất kỳ DBMS nào được hỗ trợ bởi
ODBC Driver.
• Tính khả chuyển cao nhưng kém hiệu quả.
CD1-CNPM - JAVA HIENLTH
Database
Network Interface
Server
Aplication
JDBC Driver
Native Database Library
Network Interface
Disk
Client
CD1-CNPM - JAVA HIENLTH
Native-API
•Tương tác trực tiếp với database API
•Gồm 1 phần mã Java, một phần mã của
DBMS.
CD1-CNPM - JAVA HIENLTH
JDBC - Net
• Tương tác với nhiều database theo phương thức mở
• 100% java code
• Cài đặt driver cả 2 phía client và server
Database
Network Interface
Server
Aplication
JDBC Driver Client
Network Interface
Disk
Client
JDBC Driver Server
Native Database Library
CD1-CNPM - JAVA HIENLTH
Native Protocol
• 100% java code
• Truy xuất trực tiếp DBMS theo giao thức độc quyền
• Hiệu quả nhất.
Database
Network Interface
Server
Aplication
JDBC Driver
Network Interface
Disk
Client
CD1-CNPM - JAVA HIENLTH
Các bước truy xuất CSDL
import java.sql
1. Tạo kết nối đến DBMS.
2. Tạo câu lệnh SQL nhằm thực hiện tác vụ mong muốn
3. Thi hành câu lệnh SQL
4. Xử lý kết quả trả về
5. Đóng kết nối.
CD1-CNPM - JAVA HIENLTH
Tạo kết nối
• Có 2 cách để tạo kết nối đến Datasource (DBMS, a legacy file
system,…):
• DriverManager
• DataSource
• Kết nối connection tiêu tốn tài nguyên của máy chủ DBMS
• Mở connection khi cần.
• Đóng connection khi kết thúc tác vụ.
• Connection Pool là giải pháp đa người dùng cho các ứng dụng
CSDL với số lượng người dùng lớn.
CD1-CNPM - JAVA HIENLTH
Nạp trình điều khiển JDBC (JDBC version < 4.0)
• Sử dụng phương thức tĩnh forName() của lớp Class
Class.forName (String dbDriver_Name);
• Trình điều khiển của MySQL:
dbDriver_Name = “com.mysql.jdbc.Driver”
• Trình điều khiển của Oracle:
dbDriver_Name = “oracle.jdbc.driver.OracleDriver”
• Trình điều khiển của Sybase:
dbDriver_Name = "com.sybase.jdbc.SybDriver"
• Trình điều khiển qua cầu nối ODBC (MS SQL, Access):
dbDriver_Name = “sun.jdbc.odbc.JdbcOdbcDriver”
CD1-CNPM - JAVA HIENLTH
Tạo kết nối dùng DriverManager
• Tùy theo DBMS việc kết nối có thể yêu cầu định danh
người dùng.
• DriverManager.getConnection(dbURL, user, passwd)
• DriverManager.getConnection(dbURL)
CD1-CNPM - JAVA HIENLTH
Database Connection URLs
• Là chuỗi biểu diễn địa chỉ DBMS quy định bởi JDBC driver
• Cú pháp
jdbc:<subprotocol name>: other_stuff
• subprotocol name: quy định bởi driver ghi trong tài liệu sử dụng
của driver (VD: với JDBC-ODBC driver là “odbc”)
• Other_stuff: phụ thuộc driver (VD: đối với JDBC-ODBC là Data
Source Name khai báo trong Datasource ODBC của windows)
• VD (kết nối đến MS Access)
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”)
Connection con = DriverManager.getConnection(“jdbc: odbc:ATM”);
CD1-CNPM - JAVA HIENLTH
MySQL Connector/J Database URL
• jdbc:mysql://[host][,failoverhost...] [:port]/[database]
[?propertyName1][=propertyValue1]
[&propertyName2][=propertyValue2]...
• host:port : hostname/IP and port của database server (default: 127.0.0.1:3306)
• database: Tên của database đang muốn kết nối.
• failover is the name of a standby database (MySQL Connector/J supports failover).
• propertyName=propertyValue represents an optional, ampersand-separated list of properties. These attributes enable you to instruct MySQL Connector/J to perform various tasks.
Download gói msql-connector-java-5.1.22-bin (http://www.mysql.com/products/connector/)
CD1-CNPM - JAVA HIENLTH
JDBC URL for SQL Server
jdbc:sqlserver://[serverName[\instanceName][:portNumber]][;prop
erty=value[;property=value]]
• serverName: host name or IP address of the machine on which
SQL server is running
• instanceName: name of the instance to connect to on serverName.
The default instance is used if this parameter is not specified.
• portNumber: port number of SQL server, default is 1433. If this
parameter is missing, the default port is used
• property=value: specify one or more additional connection
properties. To see the properties specific to SQL server,
visit Setting the Connection Properties.
Download Microsoft JDBC Driver 4.0 for SQL Server which supports
(http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=11774)
CD1-CNPM - JAVA HIENLTH
JDBC URL for SQL Server -Example
• Connect to default instance of SQL server running on the same machine
as the JDBC client, using Windows authentication:
jdbc:sqlserver://localhost;integratedSecurity=true;
• Connect to an instance named sqlexpress on the host dbServer, using
SQL Server authentication:
jdbc:sqlserver://dbHost\sqlexpress;user=sa;password=secret
• Connect to a named database QLHocSinh on localhost using Windows
authentication:
jdbc:sqlserver://localhost:1433;databaseName=QLHocSinh;integratedSecurity=true;
CD1-CNPM - JAVA HIENLTH
Câu lệnh Statement
• Có 3 loại Statement:
• Statement: thi hành câu lệnh tùy ý tại thời điểm chạy
• PreparedStatement: câu lệnh SQL được biên dịch trước
• CallableStatement: gọi thủ tục trên DBMS
• Sử dụng kết nối connection để tạo câu lệnh
• Statement s = con.createStatement();
• PreparedStatement ps = con.prepareStatement(String);
• CallableStatement cs = con.prepareCon(String);
• Câu lệnh Statement có thể được sử dụng nhiều lần cho
những tác vụ khác nhau, những câu lệnh SQL không
liên quan nhau.
CD1-CNPM - JAVA HIENLTH
PreparedStatements
• Câu lệnh được biên dịch trước → tăng hiệu quả thực thi.
• Cho phép thay đổi tham số mỗi lần thi hành câu lệnh SQL.
Dùng dấu chấm hỏi “?” để giữ chỗ cho mỗi tham số.
• Trước khi thi hành câu lệnh SQL, giá trị cho mỗi tham số sẽ
được đưa vào bởi hàm set<Type>() thích hợp.
• Sau khi thiết lập giá trị tham số, chúng được giữ nguyên cho
đến khi thiết lập giá trị mới hoặc gọi phương thức
clearParameter() để xóa giá trị các tham số.
CD1-CNPM - JAVA HIENLTH
PreparedStatements - VD
…
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(“UPDATE HocSinh
SET TenHS = ? , DiemTB = ? WHERE MaHS = ?”);
pstmt.setString(1, “Lê Tèo”);
pstmt.setDouble(2, 8.9);
pstmt.setString(3, “HS001”);
pstmt.executeUpdate();
…
CD1-CNPM - JAVA HIENLTH
PreparedStatements - VD
…
Connection conn = getConnection();
String sql = “SELECT * FROM HocSinh WHERE DiemTB > ?”;
PreparedStatement pstmt = conn.prepareStatement(sql,
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
pstmt.setDouble(1, 9);
ResultSet rs = pstmt.executeQuery();
…
CD1-CNPM - JAVA HIENLTH
CallableStatement
• CallableStatement cung cấp câu lệnh gọi thi hành các thủ tục đã
cài đặt sẵn trên DBMSs.
• Cú pháp:
• {call procedure_name}
• {call procedure_name [(arg1, arg2, …)]}
• {? = call procedure_name [(arg1, arg2, …)]}
• Dấu ? thay chỗ cho các đối số
• Các đối số có thể là input (IN parameters), output (OUT
parameters) hoặc cả 2 (INOUT parameters).
CD1-CNPM - JAVA HIENLTH
CallableStatement
• CallableStatement cstmt = con.prepareCall(“{call Proc(?,?)}”);
• Truyền đối số IN bằng hàm set<Type>() kế thừa từ PreparedStatement
• Đăng ký đối số OUT trước khi thi hành thủ tục
cstmt.registerOutParameter(1, Types.VARCHAR);
• Đối số INOUT
stmt1.setString(1,”00000”);
stmt1.registerOutParameter(1, Types.VARCHAR);
• Sử dùng hàm get<Type>() để nhận giá trị trả về của stored Procedure hoặc của đối số OUT.
• Các store procedure không phù hợp trong môi trường phân tán phức hợp vì nó gắn chặt với 1 DBMS cụ thể.
CD1-CNPM - JAVA HIENLTH
CallableStatements - VD
//…
try{
Connection conn = getConnection();
String proc = “CREATE PROCEDURE LayDiemCaoNhat as SELECT max(DiemTB) FROM HocSinh”;
Statement s = conn.createStatement();
s.execute(proc);
CallableStatement pstmt = conn.prepareCall(“{call LayDiemCaoNhat}”);
ResultSet rs = pstmt.executeQuery();
rs.next();
int x = rs.getDouble(1);
System.out.println(x);
//…
}catch(SQLException e){ System.out.println(e); }
//.
CD1-CNPM - JAVA HIENLTH
Thực thi Statement
• Có 3 cách thi hành Statement:
• executeQuery(select)
• executeUpdate(insert, update, delete)
• execute()
• ExecuteQuery()
• Dùng để thi hành các câu lệnh truy vấn
Select… from… where
• Trả về kết quả truy vấn qua đối tượng ResultSet
• VD: ResultSet rs = s.executeQuery(“Select * from HocSinh”);
CD1-CNPM - JAVA HIENLTH
Thực thi Statement
• executeUpdate()• Dùng cho câu lệnh cập nhật dữ liệu• Trả về số bản ghi chịu ảnh hưởng bởi câu lệnh Update,
Insert, hay Delete.• Trả về 0 khi:
• Không có bản ghi nào bị ảnh hưởng
• Hoặc thực thi câu lệnh DDL định nghĩa dữ liệu
• execute()• Khi không biết rõ câu lệnh là truy vấn hay cập nhật.• Dùng cho các trường hợp thực thi SQL động.• Trả về true nếu câu lệnh là truy vấn
• Gọi getResultSet() để nhận kết quả truy vấn.
• Gọi getUpdateCount() để biết số bản ghi đã cập nhật.
CD1-CNPM - JAVA HIENLTH
ResultSet Types
• ResultSet cho phép truy xuất đến dữ liệu trả về từ kết quả truy vấn
database
• Có 3 loại ResultSet
• TYPE_FORWARD_ONLY (default): chỉ có thể di chuyển con trỏ
theo 1 chiều tiến.
• TYPE_SCROLL_INSENSITIVE: có thể di chuyển con trỏ theo
cả 2 chiều hoặc đến vị trí bất kỳ.
• TYPE_SCROLL_SENSITIVE: có thể di chuyển con trỏ theo cả
2 chiều hoặc đến vị trí bất kỳ và có cập nhật thay đổi.
CD1-CNPM - JAVA HIENLTH
ResultSet Concurrency
• CONCUR_READ_ONLY (default): The ResultSet object
cannot be updated using the ResultSet interface.
• CONCUR_UPDATABLE: The ResultSet object can be
updated using the ResultSet interface.
• Not all JDBC drivers and databases support concurrency.
The
method DatabaseMetaData.supportsResultSetConcurrency
returns true if the specified concurrency level is supported by
the driver and false otherwise.
CD1-CNPM - JAVA HIENLTH
Cursor Holdability
• The following ResultSet constants may be supplied to the Connection methods createStatement, prepareStatement, and prepareCall:
• HOLD_CURSORS_OVER_COMMIT: ResultSet cursors are not closed; they are holdable: they are held open when the method commit is called. Holdable cursors might be ideal if your application uses mostly read-only ResultSet objects.
• CLOSE_CURSORS_AT_COMMIT: ResultSet objects (cursors) are closed when the commit method is called. Closing cursors when this method is called can result in better performance for some applications.
• The default cursor holdability varies depending on your DBMS.
CD1-CNPM - JAVA HIENLTH
ResultSet
• Loại của ResultSet phụ thuộc vào tham số truyền vào hàm
createStatement().
• VD:
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
• Có thể sử dụng cấu trúc lặp sau để duyệt một ResultSet
while(rs.next())
{
//examine a row from the results
}
CD1-CNPM - JAVA HIENLTH
ResultSet Cursors – Một số phương thứcđiều hướng
• next(): di chuyển con trỏ đến dòng kế, trả về true nếu còn dòng kế tiếp, false nếu đến cuối ResultSet.
• previous(): di chuyển con trỏ đến dòng trước.
• first(): di chuyển con trỏ đến dòng đầu tiên.
• last(): di chuyển con trỏ đến dòng cuối cùng.
• beforeFirst(): di chuyển con trỏ đến trước dòng đầu tiên.
• afterLast(): di chuyển con trỏ đến sau dòng cuối cùng.
• relative (int rows): di chuyển con trỏ tương đối với vị trí hiện tại của nó với số dòng là rows.
• absolute(int row): di chuyển con trỏ đến dòng thứ row.
• getRow(): trả về dòng hiện tại con trỏ đang đứng
• isFirst(), isLast(), isBeforeFirst(), isAfterLast(): các hàm kiểm tra.
CD1-CNPM - JAVA HIENLTH
ResultSet – Retrieving Column Values from Rows
• Lấy ra dữ liệu tại 1 cộtcủa bản ghi (dòng)
• returnTypeget<Type>(intcolumnIndex);
• returnTypeget<Type>(String columnLabel);
returnType có thể là int, double, String, Date,… Tương ứng <Type> sẽlà Int, Double, String, Date,…
CD1-CNPM - JAVA HIENLTH
ResultSet – Update rows
• Cập nhật 1 bản ghi
• Update<Type> (int
columnIndex, String x);
• Update<Type>(String
columnLabel, String x);
• updateRow(): phải gọi
hàm này để cập nhật
database
CD1-CNPM - JAVA HIENLTH
ResultSet – Insert rows
• Thêm 1 bản ghi
• moveToInsertRow();
• Update<Type> (int
columnIndex, String x);
• insertRow();
CD1-CNPM - JAVA HIENLTH
DatabaseMetadata Interface
• DatabaseMetadata là các lớp cung cấp thông tin về bản thân CSDL.
• getDatabaseProductName();• getDatabaseProductVersion();• getTableTypes();• getTables();• getTablePrivileges();
• DatabaseMetadata cũng cung cấp thông tin về JDBC Drivers
• GetDrivername();• GetDriverVersion();• GetDriverMajorVersion();• GetDriverMinorVersion();
CD1-CNPM - JAVA HIENLTH
DatabaseMetadata Interface
• DatabaseMetadata còn cung cấp thông tin về Stored
Procedures
• String getStoreProcedureTerm();
• boolean supportsStoredProcedures();
• ResultSet getProcedures();
• ResultSet getProcedureColumns();
CD1-CNPM - JAVA HIENLTH
ResultSetMetadata Interface
• ResultSetMetadata là lớp cung cấp thông tin về bản thân
ResultSet.
• getColumnCount();
• getColumnName(int column);
• getColumnType();
• VD:
ResultSet rs = stmt.executeQuery(SQLString);
ResultSetMetadata rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
CD1-CNPM - JAVA HIENLTH
Bài tập (tt)
•Yêu cầu: Viết chương trình cho phép thực hiện
các thao tác sau:
• Xem danh sách các học sinh.
• Tìm kiếm học sinh (theo mọi tiêu chí)
• Xem thông tin chi tiết một học sinh (có kèm hình
ảnh)
• Thêm/Cập nhật thông tin một học sinh
•Nộp tính điểm cộng
CD1-CNPM - JAVA HIENLTH
Transaction (Giao dịch)
• Theo mặc định, JDBC thực thi trọn vẹn các câu lệnh SQL, tức dữ
liệu sẽ được cập nhật ngay vào CSDL, gọi là autocommit.
• Một số ứng dụng mang đặc điểm transaction, tức trong 1 số
trường hợp ta muốn dữ liệu chỉ được cập nhật vào CSDL sau khi
một số câu lệnh SQL được thực hiện. Một nhóm câu lệnh như thế
gọi là 1 giao dịch.
• VD
• Đối với trang ứng dụng bán hàng qua mạng, để CSDL được thống nhất, ta chỉ muốn lưu các dữ liệu liên quan tới 1 đơn đặt hàng cùng 1 lúc.
• Đối với giao dịch chuyển tiền thông qua ATM.
CD1-CNPM - JAVA HIENLTH
Transaction - Cài đặt
Trước hết, cần tắt chế độ Autocommit. Lớp connection cung cấp
hàm setAutoCommit() để bật tắt chế độ autocommit.
con.setAutocommit(false);
• Thực hiện các câu lệnh trong một giao dịch
• Thực hiện lưu xuống CSDL.
con.commit();
• Nếu không cần dùng ở chế độ giao dịch nữa, ta nên trả lại chế độ
Autocommit
con.setAutocommit(true);
CD1-CNPM - JAVA HIENLTH
Transaction – Ví dụpublic void transaction(){
String a= “INSERT INTO PriceList VALUE (?,?);”;
if(conn != Null){
try{
conn.setAutocommit (false);
PreparedStatement ps = conn.prepareStatement(s);
ps.setString(1, “Biscuit”);
ps.setDouble(2, 1.2);
ps.executeUpdate();
ps.setString(1, “Pen”);
ps.setDouble(2, 0.5);
ps.executeUpdate();
ps.close();
conn.commit();
conn.setAutocommit(true);
} catch (SQLException e){
e.printStackTrace();
}
}
}
CD1-CNPM - JAVA HIENLTH
Transaction – Hủy
• Trong quá trình thực hiện một giao dịch, nếu có sai sót xảy
ra, ta có thể hủy giao dịch đang được thực hiện nữa chừng
bằng cách sử dụng:
conn. rollback().
• Dữ liệu ở thời điểm được commit gần nhất sẽ bị hủy. (Tùy
thuộc vào hệ quản trị CSDL mà cách rollback có thể khác
nhau).
• Dữ liệu sau khi được commit sẽ không hủy được bằng
rollback.
CD1-CNPM - JAVA HIENLTH
Transaction – Setting and rollback to a savepoint
• Save1 = con.setSavepoint: sets a Savepoint object
within the current transaction.
• Rollback to Savepoint save1: con.rollback(save1)
• Connection.releaseSavepoint takes a Savepoint object
as a parameter and removes it from the current
transaction
CD1-CNPM - JAVA HIENLTH
Transaction – Ví dụpublic void transaction(){
String a= “INSERT INTO Lop VALUES (?,?,?);”;
if(conn != Null){
try{
conn.setAutocommit (false);
PreparedStatement ps = conn.prepareStatement(s);
ps.setString(1, “10A2”); ps.setString(2, “Lớp 10A2”); ps.setDouble(3, 12);
ps.executeUpdate();
conn.commit();
ps.setString(2, “10A3”); ps.setString(2, “Lớp 10A3”); ps.setDouble(3, 1);
ps.executeUpdate();
ps.close();
conn.rollback(); //Thông tin về Lớp sẽ không được lưu vào CSDL
conn.commit();
conn.setAutocommit(true);
} catch (SQLException e){
e.printStackTrace();
}
}
}
CD1-CNPM - JAVA HIENLTH
SQLException
• SQLException.getMessage()
• SQLException.getSQLState()
• SQLException.getErrorCode()
• SQLException.getCause()
• SQLException.getNextException()
• SubClasses
• SQLNonTransientException
• SQLTransientException
• SQLRecoverableException
• BatchUpdateException
• SQLClientInfoException
CD1-CNPM - JAVA HIENLTH
Handling SQL Exception
try (Statement stmt = con.createStatement())
{
// ...
}
catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
CD1-CNPM - JAVA HIENLTH
References
• http://docs.oracle.com/javase/tutorial/jdbc/index.html
• http://codejava.net/java-se/jdbc/connect-to-microsoft-
sql-server-via-jdbc
• http://www.microsoft.com/en-
us/download/details.aspx?displaylang=en&id=11774