22
Nhập môn JDBC JDBC 1.JDBC là cái gì? JDBC (viết tắt của cụm: "Java Database Connectivity") là kiến trúc, các đặc tả, và giao diện ứng dụng dùng để truy cập dữ liệu. JDBC API là mt giao diện lập trnh s dụng SQL, nó đnh ngha các lp Java trừu tượng hóa các kết ni CSDL, các câu lệnh SQL, các tập hợp kết quả, các siêu dữ liệu ... Nó cho php mt ngưi lập trnh Java đưa ra các câu lệnh SQL và x l các kết quả được trả v. 2. Tại sao có JDBC? JDBC ra đi để ngưi viết phần mm bằng Java có mt data source access API. JDBC tách các nhà phát triển ứng dụng khi s phức tp của việc kết ni ti mt ngun dữ liệu. Tiêu chí của JDBC là nó phải d dàng cho ngưi lập trnh ứng dụng có thể to ra các kết ni của ngưi s dụng cui ti ngun dữ liệu thích hợp mà không phải tr thành mt chuyên gia v mng. Các nhà phát triển Java có thể to nên các ứng dụng truy xuất cơ s dữ liệu mà không cần phải học và s dụng các API đc quyn do các công ty sản xuất phần mm khác nhau bên thứ ba cung cấp. Bn chỉ cần học JDBC và sau đó bn sẽ được đảm bảo rằngbn sẽ có thể phát triển nên các ứng dụng truy cập cơ s dữ liệu có khả năng truy cập đến các RDBMS khác nhau bằng cách s dụng các JDBC driver khác nhau. 3. Kiến trúc của một hệ thống phần mềm dùng JDBC. JDBC được xây dng trên mô hnh kiến trúc Client/Server. Trong kiến trúc Client/Server bao gm mt mt client, mt server, và mt data protocol mà nó cho php client và server giao tiếp vi nhau. Mô hnh này rất l tưng cho mt Traditional Relational DBMS, trong đó mt mng vật l kết ni client PC ti DBMS trên mt máy khác. Các mô hnh hot đng của JDBC: - Mô hnh 2 lp (Two-tier Model): Đây là mt mô hnh kinh điển trong kiến trúc Client/Server. Các Two-Tier driver trc tiếp gi và nhận thông tin trên giao thức truyn dữ liệu của mt DBMS hoặc ánh x ti các native Database API, không trc tiếp truy xuất dữ liệu. DBMS Server nhận các yêu cầu SQL từ Client, thc hiện chúng và gi kết quả tr li Client. - Mô hnh 3 lp (Three-tier Model)

Sử dụng JDBC

Embed Size (px)

Citation preview

Page 1: Sử dụng JDBC

Nhập môn JDBC

JDBC

1.JDBC là cái gì?

JDBC (viết tắt của cụm: "Java Database Connectivity") là kiến trúc, các đặc tả, và giao diện ứng dụng dùng để truy cập dữ liệu. JDBC API là môt giao diện lập trinh sư dụng SQL, nó đinh nghia các lơp Java trừu tượng hóa các kết nôi CSDL, các câu lệnh SQL, các tập hợp kết quả, các siêu dữ liệu ... Nó cho phep môt ngươi lập trinh Java đưa ra các câu lệnh SQL và xư ly các kết quả được trả vê.

2. Tại sao có JDBC?

JDBC ra đơi để ngươi viết phần mêm bằng Java có môt data source access API. JDBC tách các nhà phát triển ứng dụng khoi sư phức tap của việc kết nôi tơi môt nguôn dữ liệu. Tiêu chí của JDBC là nó phải dê dàng cho ngươi lập trinh ứng dụng có thể tao ra các kết nôi của ngươi sư dụng cuôi tơi nguôn dữ liệu thích hợp mà không phải trơ thành môt chuyên gia vê mang. Các nhà phát triển Java có thể tao nên các ứng dụng truy xuất cơ sơ dữ liệu mà không cần phải học và sư dụng các API đôc quyên do các công ty sản xuất phần mêm khác nhau bên thứ ba cung cấp. Ban chỉ cần học JDBC và sau đó ban sẽ được đảm bảo rằngban sẽ có thể phát triển nên các ứng dụng truy cập cơ sơ dữ liệu có khả năng truy cập đến các RDBMS khác nhau bằng cách sư dụng các JDBC driver khác nhau.

3. Kiến trúc của một hệ thống phần mềm dùng JDBC.

JDBC được xây dưng trên mô hinh kiến trúc Client/Server.

Trong kiến trúc Client/Server bao gôm môt môt client, môt server, và môt data protocol mà nó cho phep client và server giao tiếp vơi nhau. Mô hinh này rất ly tương cho môt Traditional Relational DBMS, trong đó môt mang vật ly kết nôi client PC tơi DBMS ơ trên môt máy khác.

Các mô hinh hoat đông của JDBC:

- Mô hinh 2 lơp (Two-tier Model):

Đây là môt mô hinh kinh điển trong kiến trúc Client/Server. Các Two-Tier driver trưc tiếp gưi và nhận thông tin trên giao thức truyên dữ liệu của môt DBMS hoặc ánh xa tơi các native Database API, không trưc tiếp truy xuất dữ liệu. DBMS Server nhận các yêu cầu SQL từ Client, thưc hiện chúng và gưi kết quả trơ lai Client.

- Mô hinh 3 lơp (Three-tier Model)

Client trong mô hinh Three-Tier thay vi kết nôi trưc tiếp tơi DBMS, nó được kết nôi qua môt "lơp trung gian" (middle tie) là Gateway Server, sau đó lơp trung gian sẽ gưi lệnh tơi nguôn dữ liệu. Nguôn dữ liệu xư ly lệnh và trả kết quả vê cho lơp trung gian, tiếp theo lơp trung gian gưi chúng (kết quả) cho ứng dụng. Trong thưc tế, Gateway Server sẽ kết nôi tơi nhiêu DBMS. Mô hinh Three-Tier đa đưa hầu hết những sư phức tap trên Client lên Server. Nó trợ giúp rất nhiêu trong việc đơn giản hoá sư cài đặt, quản ly các driver trên Client.

Kiến trúc JDBC

Page 2: Sử dụng JDBC

Trong Java có 2 lơp chủ yếu chiu trách nhiệm vê thiết lập kết nôi đến môt cơ sơ dữ liệu.

- Lơp đầu tiên là DriverManager. Đó là môt trong rất ít các lơp thưc sư do JDBC API cung cấp. DriverManager chiu trách nhiệm quản ly môt nhóm (pool) các driver đa đă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 trinh viên không cần phải làm việc trưc tiếp vơi driver đó. Như tên gọi của nó, nhiệm vụ của nó là quản ly sư tương tác giữa các chương trinh ứng dụng và các driver, nhiêu ứng dụng và nhiêu driver có thể được quản ly cùng môt lúc. Driver Manager cung cấp sư liên kết giữa các ứng dụng và các driver, cho phep nhiêu ứng dụng truy xuất dữ liệu qua nhiêu driver. Driver Manager load hay unload môt hoặc nhiêu driver cho môt hoặc nhiêu ứng dụng. Khi môt ứng dụng cần truy xuất môt nguôn dữ liệu, Driver Manager sẽ load đúng driver cần thiết.

- Lơp thứ 2 là lơp JDBC Driver. Nó được cung cấp bơi các nhà sản xuất phần mêm đôc lập. Lơp JDBC Driver chiu trách nhiệm thiết lập đương kết nôi cơ sơ dữ liệu và xư ly tất cả các giao tiếp vơi cơ sơ dữ liệu đó: đưa ra các yêu cầu SQL để chỉ đinh các nguôn dữ liệu, và trả vê kết quả cho các ứng dụng. Các driver cung đảm nhận việc tương tác vơi bất cứ các lơp phần mêm nào cần thiết để truy xuất nguôn dữ liệu. Các JDBC driver chia thành 4 kiểu khác nhau:

o JDBC Driver loai 1- Chúng là các trinh điêu khiển cầu nôi JDBC-ODBC. Chúng ủy nhiệm công việc truy cập dữ liệu cho ODBC API. Chúng là trinh điêu khiển chậm nhất trong sô còn lai. SUN cung cấp môt phần mêm trinh điêu khiển JDBC/ODBC.

o JDBC Driver loai 2 – Chúng chủ yếu sư dụng API ma nên để truy cập dữ liệu và cung cấp các lơp bao Java để có thể được gọi ra bằng cách dùng các JDBC driver.

o JDBC Driver loai 3 – Chúng được viết thuần bằng Java và sư dụng giao thức Net đôc lập nhà sản xuất để truy cập đến trinh theo dõi từ xa đôc lập nhà sản xuất. Trinh theo dõi này đến lượt nó lai ánh xa các lơi gọi đôc lập nhà sản xuất này vào các lơi gọi phụ thuôc nhà sản xuất. Bươc đặc biệt này đa làm tăng đô phức tap và giảm tính hiệu quả trong truy cập cơ sơ dữ liệu.

o JDBC Driver loai 4 – Chúng được viết thuần túy bằng Java và là loai hiệu quả nhất. Chúng cho phep kết nôi trưc tiếp vào cơ sơ dữ liệu, cung cấp kết quả tôi ưu và cho phep lập trinh viên thưc hiện các chức năng tùy thuôc vào cơ sơ dữ liệu cụ thể. Điêu này đa tao ra tính cơ đông cao nhất là khi ban cần thay đổi cơ sơ dữ liệu bên dươi môt ứng dụng. Loai driver này thương được dùng cho các ứng dụng phân tán cao.

SUN khuyến cáo sư dụng và phát triển các trinh điêu khiển loai 4 trong các ứng dụng .

JDBC API (các gói java.sql & javax.sql )

JDBC API (API - Application Programming Interface) chứa môt tập hợp các lơp, các giao diện Java và các exception. Đa sô các API này được đinh nghia trong gói java.sql tuy nhiên sau đó Sun đưa vào thêm các API khác có tính năng cao cấp hơn có trong gói javax.sql. Sau đây là các lơp và giao diện quan trọng trong gói java. sql:

1. DriverManager - Nap các JDBC driver vào trong bô nhơ. Có thể sư dụng nó để mơ các kết nôi tơi môt nguôn dữ liệu. Tao sẵn cơ chế phân chia đương kết nôi (built-in connection pooling).

2. Connection - Biểu thi môt kết nôi đến môt nguôn dữ liệu. Được dùng để tao ra các đôi tượng Statement, PreparedStatement và CallableStatement. 3.Statement – Biểu diên môt lệnh SQL tinh. Có thể sư dụng nó để thu vê đôi tượng ResultSet.  4. PreparedStatement – Môt giải pháp thay thế hoat đông tôt hơn đôi tượng Statement, thưc thi môt câu lệnh SQL đa được biên dich trươc.

5.CallableStatement – biểu diên môt thủ tục được lưu trữ. Có thể được sư dụng để thưc thi các thủ tục được lưu trữ trong môt RDBMS có hỗ trợ chúng.

6. ResultSet - biểu diên môt tập kết quả trong cơ sơ dữ liệu tao ra bơi việc sư dụng môt câu lệnh SQL là SELECT.

7.SQLException - môt lơp xư ly lỗi ngoai lệ chứa các lỗi truy cập cơ sơ dữ liệu.

Page 3: Sử dụng JDBC

Gói thứ hai, javax.sql là môt bô phận của J2SE 1.4 và J2EE 1.3. Nó bổ sung các tính năng sau đây vào JDBC để hỗ trợ thêm cho các tính năng đa có trong gói java.sql:  8. Data sources - bao gôm các tập hợp dữ liệu và các môi trương tương ứng của chúng, bao gôm các hệ điêu hành, các DBMS, và các phần mêm mang.  19. XADataSource, XAConnection – Cho phep/Hỗ trợ các giao dich phân phôi.

10. RowSet – là wrapper của ResultSet hỗ trợ cuôn, them, xóa, sưa và phân trang. Môt ưu điểm nữa của RS2(Rowset) là nó chính là 1 Bean Component do đó ban có thể dùng nó để đăng ky vơi bất kỳ thành phần GUI(Graphics User Interface) nào và có thể thông qua đó kiểm soát các event phát sinh. CachedRowSet(CRS) cho phep cached lai dữ liệu trong memory của client và cho phep thưc thi các thao tác đông lập vơi Database server.

Đọc tìm hiểu về JDBC bạn phải có một kiến thức SQL nhất định (bài học này không đi sâu về các ngữ pháp SQL thông thường). Có rất nhiều các kiểu cơ sở dữ liệu khác nhau như Access, SQL Server ,Oracle hoặc Pointbase ... sử dụng ngôn ngữ SQL. Và mục tiêu các API của java phải hướng tới là làm thế nào dịch các mệnh lệnh của java thành mệnh lệnh mà kiểu cơ sở dữ liệu đang làm việc hiểu được và nó sẽ truy vấn dữ liệu sau đó trả về cho ứng dụng.

Database URLĐia chỉ của cơ sơ dữ liệu (Có thể nằm trên mang)( Database URL). Được sư dụng để tao kết nôi tơi cơ sơ dữ liệu. Có thể chứa tên máy chủ,cổng,giao thức,... (server, port, protocol ...)Công thức tổng quát : jdbc:subprotocol_name:driver_dependant_infoVD:

– Cầu nôi ODBC • jdbc:odbc:COREJAVA – Vơi Oracle • jdbc:oracle:thin:@machinename:1521:dbname – Pointbase • jdbc:pointbase:server://localhost/sample

Để làm việc vơi cơ sơ dữ liệu phải tao các kết nôi tơi chúng như vậy cần phải khai báo vi trí của cơ sơ dữ liệu, có thể là ngay trên máy tính, hoặc nằm môt nơi nào đó trên mang vậy cần phải cung cấp đia chỉ URL của nó. Vi vậy khi phát triển cho data base cụ thể ví dụ như Oracle hoặc Pointbase ban phải xem qua tài liệu của chúng để có chi tiết cách dùng.

Tóm lai ban phải cung cấp môt String mô tả đia chỉ vi vi trí nguôn cơ sơ dữ liệu đó ,đoan text này có thể chứa thông tin tên máy server,cổng,giai thức mang … ví dụ :"jdbc:oracle:thin:@machinename:1521:myDbname"

Đinh dang chung cho khai báo đoan text này jdbc:subprotocol_name:driver_dependant_info trong đó jdbc bao giơ cung có , sau đó subprotocol_name là tên của giao thức con , sau đó là thông tin vê điêu khiển của loai cơ sơ dữ liệu (driver_dependant_info).

MySQL và JDBC

Cài đặt MySQL

MySQL có nhiêu phiên bản cho các hệ điêu hành khác nhau: phiên bản Win32 cho các hệ điêu hành dòng Windows, Linux, Mac OSX... Connector/J - JDBC Driver của MySQL JDBC Driver của MySQL có thể lấy vê ơ đia chỉ http://www.mysql.com/downloads/api-jdbc.html .

File ban tải vê sẽ là môt file .zip hoặc .gz. Sau khi giải nen ban sẽ có 1 file có tên tương tư như sau: mysql-connectorjava- 5.1.8-stable-bin.jar. Hay chep file này vào thư mục %JAVA_HOME%/jre/lib/ext (thư mục extension của jre) trên hệ thông của ban. Ví dụ C:\Program Files\Java\jre6\lib\ext

Page 4: Sử dụng JDBC

Sau khi ban đa đặt đương dẫn đến Connector/J (file mysql-connectorjava- 5.1.8-stable-bin.jar) vào biến môi trương MYSQL_DRIVER và CLASSPATH thi ban đa có thể yên tâm là JDBC driver của MySQL đa được cài đặt xong. Kiểm tra xem Connector/J đã hoạt động chưa? Chúng ta tao ra môt chương trinh Java nho để kiểm tra xem chúng ta đa cài đặt đúng JDBC driver của MySQL chưa. Nếu chương trinh chay thành công thi nghia là trinh điêu khiển JDBC đa sẵn sàng cho các tác vụ phức tap hơn. Ban hay tao ra môt file Connect.java vơi đoan ma sau:

import java.sql.*;

public class Connect{    public static void main (String[] args) {        Connection conn = null;        try {            String userName = “root”;            String password = “localhost”;            String url = “jdbc:mysql://127.0.0.1:3306/mysql”;            Class.forName (“com.mysql.jdbc.Driver”).newInstance ();            conn = DriverManager.getConnection (url,userName, password);            System.out.println (“Da ket noi CSDL”);        }        catch (Exception e) {            System.err.println (“KHONG KET NOI DUOC”);        }        finally {            if (conn != null) {                try {                    conn.close ();                    System.out.println (“Dong ket noi”);                }                catch (Exception e) { /* bo qua loi luc dong csdl */ }            }        }    }} Trươc hết ban hay biên dich file này ra ma bytecode nhưng để chay nó, ban cần chú y đảm bảo MySQL đang chay trên máy tính cá nhân của ban. Nếu ban đa cài đặt MySQL để nó chỉ chay khi ban gọi thi ban hay bật MySQL vơi câu lệnh mysqld-nt –console hay nếu ban đa cài chương trinh quản tri cơ sơ dữ liệu này dươi hinh thức môt dich vụ thi ban có thể gõ net start mysql trong shell Run trong Windows. Đoan ma trên sư dụng cặp tên ngươi sư dụng và mật khẩu là root/localhost vơi cơ sơ dữ liệu là mysql và giao thức TCP/IP để kết nôi vào hệ cơ sơ dữ liệu MySQL.  * Phân tích

Để kết nôi và sư dụng môt cơ sơ dữ liệu từ Java applet, servlet hay ứng dụng Java thi chúng ta cần thưc hiện qua 3 bươc: 1. Đăng kí/Nap (các) driver 2. Thiết lập kết nôi đến cơ sơ dữ liệu 3. Gưi câu lệnh SQL và xư ly kết quả thu vê Bươc đầu tiên để tao ra môt kết nôi giữa ứng dụng Java và môt cơ sơ dữ liệu là đăng kí môt JDBC driver vơi máy ảo Java (JVM) mà ứng dụng Java chay trên đó. Vơi cơ chế kết nôi truyên thông (sẽ nói trong phần cơ chế kết nôi DataSource, thảo luận sau), thi kết nôi và tất cả các hinh thức giao tiếp vơi cơ sơ dữ liệu đêu do đôi tượng DriverManager kiểm soát. Để thiết lập môt đương kết nôi, môt JDBC driver thích hợp dùng cho cơ sơ dữ liệu mục tiêu phải được đăng kí vơi đôi tượng DriverManager. Đặc tả JDBC chỉ ra rằng các JDBC driver được xem là sẽ tư đăng kí vơi đôi tượng DriverManager môt cách tư đông khi chúng được nap vào môt JVM. Ví dụ đoan ma sau sư dụng môt bô khơi tao tinh để lần đầu tiên tao ra môt mẫu của JDBC driver mang tên persistentjava và sau đó đăng kí nó vơi DriverManager. static {java.sql.DriverManager.registerDriver(new

Page 5: Sử dụng JDBC

com.persistentjava.JdbcDriver()) ;}

Việc đăng kí môt driver đơn giản chỉ là việc nap lơp driver vào JVM. Chúng ta có thể làm điêu đó bằng môt sô cách khác nhau. Môt trong những cách đó là thông qua  ClassLoader Class.forName(com.persistentjava.JdbcDriver) ;. Môt cách khác, không phổ biến lắm là dùng thuôc tính hệ thông jdbc.drivers. Chúng ta có thể dùng cách này theo 3 hinh thức khác nhau: Từ dòng lệnh:java -Djdb.drivers =com.persistentjava.JdbcDriver Connect  * Bên trong ứng dụng java:  System.setProperty(“jdbc.drivers”, “com.persistentjava.JdbcDriver”) ;

  * Bằng cách thiết lập thuôc tính jdbc.drivers vào file thuôc tính hệ thông, nhưng nhin chung là lai tùy thuôc vào hệ thông Bằng phương pháp tách các driver bằng môt dấu phẩy, chúng ta có thể đăng kí nhiêu driver thông qua ki thuật thuôc tính hệ thông ơ trên. Môt trong các lợi ích của ki thuật này là ơ chỗ các driver có thể đưa vào và ra khoi JVM mà không cần thay đổi ma (hoặc chỉ cần thay đổi ơ mức tôi thiểu). Nếu đăng kí nhiêu driver, thứ tư ưu tiên của chúng như sau: 1)Các JDBC driver do thuôc tính jdbc.drivers đăng kí lúc khơi tao JVM, và 2)Các JDBC driver được nap đông. Do thuôc tính jdbc. drivers chỉ được kiểm tra môt lần vào lần gọi đầu tiên của phương thức DriverManager(), nên quan trọng là ban phải đảm bảo rằng tất cả các driver được đăng kí đúng trươc khi thiết lập kết nôi.Chú y là có môt sô JVMs không tuân thủ đặc tả JVM và kết quả là các bô khơi tao tinh không phải lúc nào cung làm việc thông nhất như mong muôn. Điêu này dẫn tơi việc có nhiêu cách đăng kí môt JDBC driver:Class.forName(”com.persistentjava. JdbcDriver”).newInstance() ;HoặcDriverManager.registerDriver(new com.persistentjava.JdbcDriver()) ; Hai cách trên thương hoat đông tôt trong tất cả các JVM nên ban có thể sư dụng chúng môt cách thoải mái. Nhưng điêu khác biệt là Class.forName() có thể chặn bắt môt ClassNotFoundException, nên ban cần bao ma đăng kí driver vào môt bô xư ly lỗi ngoai lệ thích hợp.Ví dụ:

try{Class.forName (“com.mysql.jdbc.Driver”).newInstance ();}catch (Exception e){System.err.println (“KHONG KET NOI DUOC”);} Các sách vê MySQL khuyến cáo ban nên dùng cách trên. Phương thức Class.forname() nhận môt chuỗi làm đôi sô. Trong trương hợp ban dùng JDBC Driver của hang MySQL AB cho MySQL bản 4.0 trơ lên thi chuỗi đó là:  com.mysql.jdbc.Driver

Cần chú y là ban không cần phải tao ra môt mẫu của driver và đăng kí nó vơi DriverManager vi việc gọi Class.forName() sẽ làm cho ban điêu đó môt cách tư đông.Bươc tiếp theo sau khi ban đa đăng kí JDBC Driver là thưc hiện kết nôi. Toàn bô công đoan này được minh họa qua dòng ma sau: Connection conn = DriverManager.getConnection(url, “myLogin”, “myPassword”);

Phương thức getConnection() được gọi để thưc hiện môt kết nôi thưc sư đến phần mêm máy chủ cơ sơ dữ liệu. Lơp DriverManager tao ra môt đôi tượng Connection khi ban gọi phương thức getConnection(). Phương thức này nhận môt chuỗi URL làm đôi sô. Ví dụ, vơi MySQL thi chuỗi đó có thể là: jdbc:mysql://127.0.0.1:3306/mysql hoặc jdbc:mysql://localhost/mydatabase Chuỗi này tuân theo quy tắc sau đây: jdbc:<subprotocol>:<subname> trong đó:<subprotocol> thương là driver hoặc cơ chế kết nôi cơ sơ dữ liệu <subname> phụ thuôc vào <subprotocol>, có thể thay đổi theo các nhà cung cấp driver mà nó có thể là mysql, db2, oracle hay odbc.<subname> có thể chứa đia chỉ Internet cho các cơ sơ dữ liệu ơ xa. Phần này có thể gôm có tên host, ma sô cổng, và tên của hệ thông cơ sơ dữ liệu.  Chú y là trong môt sô sách khác, công thức trên còn trinh bày dươi dang: jdbc:sub-protocol:database locator tuy vê bản chất thi không có gi thay đổi. Nếu môt trong các driver mà ban cung cấp nhận ra đia chỉ JDBC URL mà ban cung cấp cho phương thức DriverManager.getConnection, thi driver đó sẽ thiết lập đương kết nôi đến MySQL xác đinh trong JDBC URL. Lơp DriverManager sẽ quản ly tất cả các chi tiết của việc thiết lập đương kết nôi bên dươi nên ban không cần phải quan

Page 6: Sử dụng JDBC

tâm gi thêm. Đương kết nôi do phương thức DriverManager.getConnection trả vê là môt đương kết nôi mơ mà ban có thể sư dụng để thông qua các lệnh JDBC nhằm gưi các lệnh SQL tơi MySQL. Ở đây chúng ta có đôi tượng conn chứa kết nôi mơ và chúng ta sẽ sư dụng chúng để thưc hiện các ví dụ thao tác trên MySQL

Thực hiện các câu truy vấn

Để thưc hiện câu lệnh SQL trong môt ứng dụng có sư dụng JDBC, ban hay tao ra môt đôi tượng Statement từ đôi tượng Connection của ban. Đôi tượng này chứa môt kết nôi đơn đến cơ sơ dữ liệu. Các đôi tượng Statement hỗ trợ phương thức executeUpdate() để đưa vào các câu truy vấn thưc hiện chức năng thay đổi cơ sơ dữ liệu và không trả lai tập kết quả, và phương thức executeQuery() để tao ra các câu truy vấn cho phep trả lai tập kết quả. Để minh họa kết quả xư ly dữ liệu chúng ta sư dụng môt bảng, animal, bảng này hứa 1 côt id chứa sô nguyên và 2 côt chứa các chuỗi, name và category. Câu lệnh MySQL để tao bảng này trông như sau:

   CREATE TABLE animal(        id INT UNSIGNED NOT NULL AUTO_INCREMENT,         PRIMARY KEY (id),

        name CHAR(40),

        category CHAR(40)    )

Côt id có thuôc tính AUTO_INCREMENT tức là giá ri của nó tư đông tăng thêm mà không cần chúng ta rưc tiếp can thiệp, vi MySQL tư đông gán các giá tri ôi tiếp nhau 1, 2, 3, ... mỗi khi có 1 bản ghi được bổ sung vào bảng.

Thực hiện câu truy vấn không trả lại tập kết quả

Đầu tiên chúng ta tao ra môt đôi tượng Statement từ đôi tượng Connection, và sau đó sư dụng chúng để tao ra và cung cấp giá tri cho bảng animal. DROP TABLE, CREATE TABLE, UPDATE, DELETE và INSERT đêu là các câu lệnh thưc hiện việc thay đổi cơ sơ dữ liệu, cho nên phương thức executeUpdate() là phương thức thích hợp để thưc thi chúng. Phương thức này trả lai môt sô nguyên chỉ sô lượng hàng trong cơ sơ dữ liệu đa bi tác đông sau khi thưc hiện câu truy vấn. Trong ví dụ dươi đây, sô nguyên này đa được gán vào biến count:

    Statement s = conn.createStatement ();    int count;    s.executeUpdate (“DROP TABLE IF EXISTS animal”);    s.executeUpdate ( “CREATE TABLE animal (“ + “id INT UNSIGNED NOT NULL                     AUTO_INCREMENT,”        + “PRIMARY KEY (id),”        + “name CHAR(40), category CHAR(40))”);    count = s.executeUpdate (“INSERT INTO animal (name, category)”        + “ VALUES”        + “(‘snake’, ‘reptile’),”        + “(‘frog’, ‘amphibian’),”        + “(‘tuna’, ‘fish’),”        + “(‘racoon’, ‘mammal’)”);    s.close();    System.out.println (count + “ dong da duoc tao ra”);

Ở đây, biến count được sư dụng để báo lai sô lượng hàng mà câu lệnh INSERT đa bổ sung vào bảng animal.

Môt đôi tượng Statement có thể sư dụng để tao ra nhiêu câu truy vấn. Khi đa thưc hiện xong các thao tác trên cơ sơ dữ liệu, ban hay gọi phương thức close()để xóa đôi tượng và giải phóng tất cả các tài nguyên liên kết đến nó.

Nếu như ban muôn biết câu lệnh SQL có trả lai tập kết quả hay không (ví dụ như khi ngươi sư dụng nhập câu lệnh vào trương nhập liệu của form), thi ban có thể dùng phương thức execute() của đôi tượng Statement. Phương thức này trả lai true nếu câu lệnh có trả lai tập kết quả. Trong trương hợp đó, đôi tượng ResultSet có thể được thu hôi thông qua phương thức getResultSet() và sô lượng hàng được tác đông có thể biết được thông qua phương thức getUpdateCount():

    Statement unknownSQL = con.createStatement();

Page 7: Sử dụng JDBC

    if(unknownSQL.execute(sqlString)) {        ResultSet rs = unknownSQL.getResultSet();        // hiển thị kết quả    }    else {        System.out.println(“Cac dong da cap nhat: “ + unknownSQL.getUpdateCount());    }

Thực thi các câu truy vấn có trả lại một tập kết quả Các câu lệnh truy vấn có trả lai tập kết quả là các câu lệnh giúp chúng ta lấy ra dữ liệu từ cơ sơ dữ liệu dươi môt dang thức nào đó. Ví dụ câu lệnh SELECT lấy thông tin từ môt cơ sơ dữ liệu vê thi khi đó ta dùng phương thức executeQuery(). Sau khi gọi phương thức này, ban hay tao ra môt đôi tượng ResultSet và sư dụng nó để lặp lai các thao tác dữ liệu trên các hàng mà câu truy vấn trả vê. Ví dụ sau cho thấy cách sư dụng phương thức này để lấy thông tin từ bảng animal vê:

    Statement s = conn.createStatement ();    s.executeQuery (“SELECT id, name, category FROM animal”);    ResultSet rs = s.getResultSet ();    int count = 0;    while (rs.next ()){        int idVal = rs.getInt (“id”);        String nameVal = rs.getString (“name”);        String catVal = rs.getString (“category”);        System.out.println ( “id = “ + idVal + “, name = “ + nameVal + “, category = “ +             catVal);        ++count;    }    rs.close ();    s.close ();    System.out.println (count + “ dong duoc thu ve”);

Phương thức executeQuery() không trả lai sô nguyên đếm sô hàng mà nó tác đông, do vậy nếu ban muôn biết môt tập kết quả chứa bao nhiêu hàng thi ban cần tư minh đếm lấy khi ban thưc thi thao tác lấy dữ liệu trên từng hàng. Để lấy được các giá tri của côt trên từng hàng, thi ban hay gọi các phương thức getXXX(),trong đó XXX đai diện cho kiểu giá tri của côt. Chẳng han, các phương thức getInt() và getString() được sư dụng trong ví dụ trên trả lai các giá tri chuỗi và sô nguyên. Như đa trinh bày, các phương thức này có thể được gọi bằng cách sư dụng tên của môt côt nằm trong tập kết quả. Ban cung có thể lấy các giá tri vê từ vi trí của chúng. Đôi vơi tập kết quả lấy vê từ câu truy vấn SELECT trong ví dụ trên, id, name, và category nằm ơ các vi trí côt 1, 2 và 3 và do vậy có thể lấy vê theo cách sau:

    int idVal = rs.getInt (1);    String nameVal = rs.getString (2);    String catVal = rs.getString (3);   Các đôi tượng ResultSet, cung như các đôi tượng Statement, nên được đóng lai khi ban đa dùng xong chúng. Để kiểm tra xem liệu giá tri của môt côt nào đó có là NULL hay không, ban hay gọi phương thức wasNull() của đôi tượng chứa tập kết quả sau khi lấy giá tri đó vê. Ví dụ, ban có thể kiểm tra giá trí NULL nằm trong côt name như sau:

    String nameVal = rs.getString (“name”);    if (rs.wasNull ())        nameVal = “(khong ten)”;

Xử lý lỗi

Nếu ban muôn bẫy lỗi, hay thưc thi các thao tác JDBC bên trong khôi try và sư dụng môt bô xư ly lỗi ngoai lệ để hiển thi thông tin vê nguyên nhân gây ra vấn đê có thể xuất hiện. JDBC cung cấp các phương thức getMessage() và getErrorCode() mà khi lỗi xuất hiện ban có thể sư dụng để biết được thông báo lỗi và ma lỗi dang sô. Ví dụ sau cô tinh dùng môt câu truy vấn mắc lỗi. Khi thưc thi, phương thức executeQuery() sẽ không thể xư ly được và phát sinh môt lỗi ngoai lệ. Lỗi này sẽ được thu vê thông qua khôi catch, trong khôi này ban có thể chứa ma lệnh để xư ly lỗi hay chỉ đơn giản là hiển thi thông báo lỗi và ma lỗi:

Page 8: Sử dụng JDBC

    try{         Statement s = conn.createStatement ();        s.executeQuery(“XYZ”); // tạo ra câu truy vấn không hợp lệ        s.close();    } catch(SQLException e) {        System.err.println (“Thong bao loi: “ + e.getMessage());        System.err.println (“Ma loi: “ +\e.getErrorCode());    }

Chúng ta tiếp tục đi sâu vô môt tí xíu và làm quen vơi ResultSetMetaData, Statement và PreparedStatement.

Các thành phần JDBC

1.MetaData

Hẳn ban đa nghe đến thuật ngữ này, có sách dich là “siêu dữ liệu”, cái khác thi dich là “dữ liệu của dữ liệu”, còn tôi thi chẳng dám dich

ra Tiếng Việt, thành thư cứ giữ nguyên là metadata.

Phương thức getMetaData() của ResultSet sẽ trả vê cho ban môt đôi tượng của kiểu ResultSetMetaData, đôi tượng này chứa thông

tin vê ResultSet. Như ban đa biết, bên trong ResultSet thưc chất là môt table được trả vê từ câu lệnh truy vấn, metadata của ResultSet

sẽ là: sô côt của table, tên của các côt, tên của table...Chúng ta hay xem qua ví dụ:

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.ResultSetMetaData;

import java.sql.SQLException;

import java.sql.Statement;

public class MetaDataExample {

private static String driver = "org.gjt.mm.mysql.Driver";

private static String url = "jdbc:mysql://localhost:3306/test";

private static String username = "root";

private static String password = "";

public static void main(String[] args) {

try {

Class.forName(driver);

Connection conn = DriverManager.getConnection(url, username, password);

String query = "SELECT * FROM books";

Statement stm = conn.createStatement();

ResultSet rs = stm.executeQuery(query);

// Lay ve resultset metadata

ResultSetMetaData metadata = rs.getMetaData();

System.out.print("Ten cua table:");

System.out.println(metadata.getTableName(1));

System.out.print("So cot trong table:");

Page 9: Sử dụng JDBC

System.out.println(metadata.getColumnCount());

System.out.print("Ten cua cot thu 1:");

System.out.println(metadata.getColumnName(1));

System.out.print("Cot thu nhat co phai la auto increment ko?:");

System.out.println(metadata.isAutoIncrement(1));

//System.out.println(metadata.getColumnType(1));

}

catch(ClassNotFoundException cnfe) {

cnfe.printStackTrace();

}

catch(SQLException sqle) {

sqle.printStackTrace();

}

}

}

Output:

Ten cua table:books

So cot trong table:3

Ten cua cot thu 1:isbn

Cot thu nhat co phai la auto increment ko?:true

2.Statement

Chúng ta cung đa nói sơ vê Statement trong bài trươc. Statement là môt interface, nó đinh nghia các phương thức để giúp ban tương

tác vơi database. Phương thức createStatement() của đôi tượng Connection sẽ trả vê cho ban môt đôi tượng mà implement Statement

interface này.

* Giới hạn số dòng trả về.

Thông thương khi ban thưc hiện câu lệnh truy vấn ban sẽ không biết có bao nhiêu hàng trong ResultSet được trả vê. Statement cho

phep ban giơi han sô dòng thông qua phương thức setMaxRows(...), ban cung có thể lấy vê sô dòng tôi đa bằng phương thức

getMaxRows(). Lưu y là giá tri 0 có nghia là không giơi han.

* Time-out cho câu lệnh truy vấn

Ban có thể thiết lập time-out cho môt câu lệnh truy vấn thông qua phương thức setQueryTimeout() và ban cung có thể lấy vê giá tri của

time-out bằng phương thức getQueryTimeout(). Giá tri 0 có nghia là không giơi han.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

public class StatementExample {

private static String driver = "org.gjt.mm.mysql.Driver";

private static String url = "jdbc:mysql://localhost:3306/test";

private static String username = "root";

private static String password = "";

public static void main(String[] args) {

Page 10: Sử dụng JDBC

try {

Class.forName(driver);

Connection conn = DriverManager.getConnection(url, username, password);

Statement stm = conn.createStatement();

int mr = stm.getMaxRows();

System.out.println("Maximum Rows: " + (mr == 0 ? "No Limit" : mr + ""));

int timeout = stm.getQueryTimeout();

System.out.println("Time-out:" + (timeout == 0 ? "No Limit" : timeout + ""));

// String ins = "INSERT INTO books(title, publisher) VALUES('C# can ban', 'NXB Kim Dong')";

// stm.executeUpdate(ins);

//

// String update = "UPDATE books SET title='Lap trinh can ban' WHERE isbn=1";

// stm.executeUpdate(update);

}

catch(ClassNotFoundException cnfe) {

cnfe.printStackTrace();

}

catch(SQLException sqle) {

sqle.printStackTrace();

}

}

}

Output:

Maximum Rows:No Limit

Time-out:No Limit

* Làm việc với DDL và DML

DDL là viết tắt của data definition language, như CREATE TABLE hay DROP TABLE.

DML là viết tắt của data manipulation language, như INSERT, DELETE, UPDATE

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

public class StatementExample {

private static String driver = "org.gjt.mm.mysql.Driver";

private static String url = "jdbc:mysql://localhost:3306/test";

private static String username = "root";

private static String password = "";

public static void main(String[] args) {

try {

Page 11: Sử dụng JDBC

Class.forName(driver);

Connection conn = DriverManager.getConnection(url, username, password);

Statement stm = conn.createStatement();

String ins = "INSERT INTO books(title, publisher) VALUES('C# can ban', 'NXB Kim Dong')";

stm.executeUpdate(ins);

String update = "UPDATE books SET title='Lap trinh can ban' WHERE isbn=1";

stm.executeUpdate(update);

String delete = "DELETE FROM books WHERE isbn=2";

stm.executeUpdate(delete);

}

catch(ClassNotFoundException cnfe) {

cnfe.printStackTrace();

}

catch(SQLException sqle) {

sqle.printStackTrace();

}

}

}

3.PreparedStatement

Quay lai vơi Statement môt chút, khi ban muôn thưc hiện môt câu lệnh SQL vơi Statement ban phải truyên vào môt String, chuỗi này là

câu lệnh mà ban muôn thưc hiện. Ví dụ vơi table books ơ bài viết trươc, ban muôn thưc hiện truy vấn chọn ra cuôn sách dưa vào isbn

của nó. Nếu sư dụng Statement, mỗi lần ban phải truyên vào chuỗi như thế này:

SELECT * FROM books WHERE isbn = 1 (lần 1)

SELECT * FROM books WHERE isbn = 2 (lần 2)

SELECT * FROM books WHERE isbn = 3 (lần 3)

Ở bên dươi, mỗi lần thưc hiện môt câu lệnh thi database lai làm nhiệm vụ phân tích (parse) chuỗi truy vấn, sau đó compile nó sang

ngôn ngữ mà database có thể hiểu được. Công việc này làm đi làm lai nhiêu lần sẽ ảnh hương tơi hiệu suất của chương trinh, đặc biệt

là vơi database có lượng dữ liệu lơn. Làm thế nào để câu lệnh SQL chỉ được phân tích và compile môt lần, may mắn là chúng ta đa có

PreparedStatement. Lúc này câu lệnh của ban chỉ còn lai thế này:

SELECT * FROM books WHERE isbn = ?

Ky tư “?” đây có y nghia: dành trươc môt chỗ để sau này muôn thưc hiện câu lệnh trên chỉ cần set giá tri cho isbn là được.

PreparedStatement pstm = connection.prepareStatement(“SELECT * FROM books WHERE isbn = ?”);

pstm.setInt(1, 1);

ResultSet rs = pstm.executeQuery();

Trươc khi thưc hiện câu lệnh SQL, ban phải gán giá tri cho những chỗ có ky tư “?”. Thứ tư lần lượt của các ky tư “?” sẽ bắt đầu từ 1

PreparedStatement pstm = connection.prepareStatement(“SELECT * FROM books WHERE isbn = ? AND title = ?”);

pstm.setInt(1, 1);

Page 12: Sử dụng JDBC

pstm.setString(2, “Lap trinh Java”);

ResultSet rs = pstm.executeQuery();

PreparedStatement đinh nghia môt tập hợp các phương thức setXXX() để ban gán giá tri

setString()

setInt()

setBoolean()

setObject()

...

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

public class PreparedStatementExample {

private static String driver = "org.gjt.mm.mysql.Driver";

private static String url = "jdbc:mysql://localhost:3306/test";

private static String username = "root";

private static String password = "";

public static void main(String[] args) {

try {

Class.forName(driver);

Connection conn = DriverManager.getConnection(url, username, password);

String ins = "INSERT INTO books(title, publisher) VALUES(?, ?)";

PreparedStatement pstm = conn.prepareStatement(ins);

pstm.setString(1, "Nghe thuat song");

pstm.setString(2, "NXB Tre");

pstm.executeUpdate();

String update = "UPDATE books SET title=? WHERE isbn=?";

PreparedStatement pstm1 = conn.prepareStatement(update);

pstm1.setString(1, "Title");

pstm1.setInt(2, 1);

pstm1.executeUpdate();

}

catch(ClassNotFoundException cnfe) {

cnfe.printStackTrace();

}

catch(SQLException sqle) {

sqle.printStackTrace();

}

}

}

Page 13: Sử dụng JDBC

4.Sử dụng đối tượng ResultSet

Đôi tượng ResultSet trong lập trinh JDBC rất quan trọng, nó lưu giữ các mẫu tin thoa man 1 tính chất nào đó của

database, cho phep thưc hiện các thao tác trên nó,…

ResultSet có được khi chúng ta thưc thi 1 câu select SQL từ đôi tượng xStatement. Sau khi có được đôi tượng ResultSet

ta có thể đọc 1 mẫu tin bằngphương thức next(). Phương thức này trả vê false khi không có mẫu tin để đọc (có thể là

cuôi danh sách). Sau khi đọc 1 mẫu tin, ta có thể lấy dữ liệu từ mẫu tin hiện tai bằng cách dùng các phương thức

getXXX(”fieldName hoặc index”) trong đó XXX là kiểu dữ liệu của field cần đọc. Vi do kiểu của csdl và kiểu của java là

không giông nhau nên ta phải chú y ánh xa từ kiểu của csdl sang kiểu của java tương ứng. Tuy nhiên trong 1 sô trương

hợp, jdbc tư ep kiểu cho chúng ta theo nguyên tắc của việc chuyển kiểu.

Vê tham sô truyên vào phương thức getXXX, tôi nghi là chúng ta nên truyên vào tên field thay thi chỉ sô index vô tri vô

giác. Lưu y: trong lập trinh JDBC, index luôn bắt đầu từ 1. Vi dụ :

void TestExecuteQuery() {    try {        con=ConnectDBFactory.CreateMsSqlServerConnection("BookMS");        Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);        String sql1="select * from book";        ResultSet rs=stmt.executeQuery(sql1);        while(rs.next()) {            String ms=rs.getString("isbn");            String mk=rs.getString("bookTiitle");            System.out.println(ms+"\t"+mk);        }        rs.previous();        String ms=rs.getString("isbn");        System.out.println("Sau khi di lui");        System.out.println(ms);    } catch (Exception e) {        e.printStackTrace();    } finally {        try {            con.close();        } catch (SQLException e) {            e.printStackTrace();        }    }}

5.Xử lý theo khối (batch processing) • Nhóm nhiêu câu lệnh vào trong môt khôi (batch) . Sau đó thi hành cả môt khôi lệnh cùng môt lúc . • Thêm lệnh vào khôi lệnh

  - Method addBatch(String sql) (java.sql.Statement)- Method addBatch() (java.sql.PreparedStatement )

• Thi hành khôi lệnh- Method executeBatch() (java.sql.Statement)

 

Ví dụ vơi việc xư ly theo khôi (batch processing)

// Một kết nối tới một cơ sở dữ liệu nào đó Connection connection = .... ;

Page 14: Sử dụng JDBC

 Statement statement=connection.createStatement(); //Thêm một nhiệm vụ vào khối (DELETE )  statement.addBatch("DELETE FROM Account WHERE id=200"); // accounts là một mảng đối tượng Java . for(int i=0;i<accounts.length;i++){   // Thêm một nhiệm vụ vào khối (UPDATE).   statement.addBatch("UPDATE Account "+                     "SET balance="+accounts[i].getBalance()+                     " WHERE id="+accounts[i].getId()); } /** Thi hành cả khối nhiệm vụ.Trong đó int[] rows là mảng , mà mỗi phần tử là    số hàng bị tác động bởi từng lệnh (nhiệm vụ ) trong khối */ int[] rows=statement.executeBatch();

Ví dụ sư khác nhau giữa các bươc sư dụng PreparedStatement và batch ?

String sql="UPDATE Account SET balance=? WHERE id=?"; // Chuẩn bị câu lệnh SQL được dịch sẵn . PreparedStatement pstm=connection.preparedStatement(sql); //accounts là một mảng đối tượng Java . for(int i=0;i<accounts.length;i++){   pstm.setFloat(1,accounts[i].getBalance());   pstm.setInt(2,accounts[i].getId());   //Thêm nhiệm vụ này vào khối .   pstm.addBatch(); } //Thi hành cả khối lệnh   pstm.executeBatch();

• Đoan code trên đây là môt ví dụ minh họa việc UPDATE đông loat các hàng trong bảng Account trong cơ sơ dữ liệu vơi Batch .Trươc đây chúng ta đa làm việc tương tư này sư dụng PreparedStatement .Hay nhin vào bảng so sánh các bươc đa làm của 2 cách .

PreparedStatement Sư ly theo khôi (Batch processiong)

1) Tắt bo chế đô tư đông commit .2) Chuẩn bi đôi tượng PreparedStatement . 3) Gán giá tri (Tai vi trí cho các dấu ? ) 4) Thi hành (execute ) (Nhưng thay đổi chưa diên ra trong DataBase ). 5) Lặp lai bươc 3,4 nhiêu lần (phụ thuôc vào ứng dụng) 6) Gọi method commit() (Tao thay đổi đông loat diên ra trong Database) .

1) Chuẩn bi đôi tượng PreparedStatement . 2) Gán các giá tri (tai các vi trí dấu ?) 3) Thêm vào khôi . 4) Lặp lai bươc 2,3 nhiêu lần phụ thuôc vào ứng dụng . 5) Thưc thi khôi lệnh .

 

6.CallableStatement

Phần này giơi thiệu vơi các ban cách chúng ta thao tác vơi các StoredProcedure trong java vơi đôi tượng CallableStatement.

CallableStatement là đôi tượng kế thừa từ đôi tượng PreparedStatement, như vậy có các tính chất của 1 PreparedStatement (tức có các tính chất của Statement(public interface CallableStatement extends PreparedStatement). Chúng ta tao 1 CallableStatement bằng cú pháp sau:

CallableStatement prepareCall(String sql) throws SQLException hoặc

CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException.

Sau đó chúng ta triệu gọi các stored procedure bằng các cú pháp sau:

Page 15: Sử dụng JDBC

Đôi vơi procedure không có tham sô: {call procedure_name}

Đôi vơi procedure có tham sô: {call procedure_name(?,?,…)}

Đôi vơi procedure có giá tri trả vê (function): {?=call procedure_name(?,?,…)}

Ví dụ: CallableStatement cstmt = con.prepareCall(”{call procedureName(?, ?)}”);

trong đó các dấu ? thay thế cho các tham sô kiểu IN, OUT, INOUT.

Đôi vơi tham sô kiểu IN, ta sư dụng phương thức setXXX của đôi tượng PrepareStatement để chuyển tham sô vào. ví dụ: cstmt.setString(1, “c%”);

Đôi vơi tham sô kiểu OUT, ta phải đăng ky đầu ra trươc khi thưc thi, ví dụ: stmt.registerOutParameter(1, java.sql.Types.INTEGER);

Đôi vơi tham sô dang INOUT, ta kết hợp gôm IN và OUT.

Cho dê hiểu, tôi sẽ viết 1 ví dụ thưc thi các kiểu StoredProcedure cho các ban.

Trươc hết ta tao 1 database có tên QLSV trong đó có 1 bảng có tên Lophoc . SQL script cho database như sau:

CREATE TABLE [dbo].[Lophoc]([classID] [nvarchar](15) COLLATE Vietnamese_CI_AS NOT NULL,[className] [nvarchar](100) COLLATE Vietnamese_CI_AS NOT NULL,[studentsNum] [int] NOT NULL,[deptID] [nvarchar](15) COLLATE Vietnamese_CI_AS NULL,CONSTRAINT [PK_tblClass] PRIMARY KEY CLUSTERED([classID] ASC)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]) ON [PRIMARY]

Sau đó chúng ta tao các procedure để thư.  Script sau đây sẽ tao các stored procedure cho chúng ta:

–Tao proc cho tham sô INcreate proc exInparams@clsID varchar(15)ASselect *from tblClasswhere tblClass.classID like @clsIDGO–Thưc thiexec exInparams ‘c%’–********************************************-Tao proc cho tham sô outputcreate proc exOutParams@cls varchar(15),@num int OUTPUTasselect @num=count(classID)from tblClasswhere classID like @clsgo–Thưc thideclare @s intexec exOutParams ‘c%’,@s OUTPUTprint @s–********************************************-Tao proc cho tham sô INOUT

Page 16: Sử dụng JDBC

create proc exINOUTParams@num int OUTasselect @num=count(classID)from tblClasswhere studentsNum>@numgoselect * from tblClass–Thưc thideclare @s intset @s=100exec exINOUTParams @s OUTPUTprint @s–********************************************–Hàm Function–Hàm lấy sô SV của 1 lơp khi biết ma sô lơpcreate FUNCTION dbo.getNoStudents (@classID varchar(15))RETURNS intASBEGINDeclare @c  intset @c=(select studentsNum from tblClass where classID = @classID)return @cENDgo–Thưc thideclare @x intset @x=dbo.getNoStudents(’cdth4c’)print(@x)–********************************************

Ban tao DB rôi chay các hàm để thư trên hệ quản tri CSDL, chẳng han MS SQLserver.

ban tao lơp sau để thư các loai:

import java.sql.*;

//thử tham số đầu vàopublic class TestCallable {

    private Connection con;

    void TestINPro() throws Exception {        con = ConnectDBFactory.CreateMsSqlServerConnection("QLSV");        String sql = "{call exInparams(?)}";        CallableStatement cstmt = con.prepareCall(sql);        cstmt.setString(1, "c%");        ResultSet rs = cstmt.executeQuery();        while (rs.next()) {            System.out.println(rs.getString("className"));        }        con.close();    }//thử tham số đầu ra    void TestOUTPro() throws Exception {        con =                ConnectDBFactory.CreateMsSqlServerConnection("QLSV");        String sql = "{call exOutParams(?,?)}";        CallableStatement cstmt = con.prepareCall(sql);        cstmt.setString(1, "d%");//đăng ký tham số đầu ra        cstmt.registerOutParameter(2, java.sql.Types.INTEGER);

Page 17: Sử dụng JDBC

        cstmt.execute();//Lấy giá trị trả về        int s = cstmt.getInt(2);        System.out.println(s);        con.close();    }//Thử tham số vừa vào vừa ra    void TestINOUTPro() throws Exception {        con = ConnectDBFactory.CreateMsSqlServerConnection("QLSV");        String sql = "{call exINOUTParams(?)}";        CallableStatement cstmt = con.prepareCall(sql);        cstmt.setInt(1, 200);//Đăng ký tham số đầu ra        cstmt.registerOutParameter(1, java.sql.Types.INTEGER);        cstmt.execute();//lấy giá trị trả về        int s = cstmt.getInt(1);        System.out.println(s);        con.close();    }//Thử việc triệu gọi 1 function có giá trị trả về    public void TestFunctionCall() throws Exception {        ConnectDBFactory.CreateMsSqlServerConnection("QLSV");        CallableStatement cst = con.prepareCall("{?=call getNoStudents(?)}");        cst.registerOutParameter(1, java.sql.Types.INTEGER);        cst.setString(2, "CD");        cst.execute();        int ret = cst.getInt(1);        System.out.println("Số sinh viên: " + ret);    }}

7.TransactionKhái niệm vê môt giao dich (transaction) là môt khái niệm quan trọng , vơi các lập trinh viên thi việc đôi mặt vơi xư ly giao dich là tương đôi thương xuyên . Môt trong các ví dụ kinh điển vê giao dich có thể đưa ra là ứng dụng vê chuyển khoản giữa 2 công ty A và B .Công ty A muôn chuyển môt khoản tiên X đến cho công ty B như vậy trong logic ứng dụng sẽ phải xẩy ra 2 công đoan môt là trừ sô tiên X ra khoi tài khoản của A và hai là thêm vào tài khoản của B sô tiên X . Điêu gi sẽ xẩy ra khi ứng dụng viết có sai sót sô tiên của A bi trừ đi nhưng bươc tiếp theo là thêm khoản tiên vào cho B không thưc hiện . Transaction có thể coi là môt nhóm công việc không thể chia cắt , chỉ môt công việc trong nhóm không thành công thi giao dich gọi là không thành công . Trong tinh huông trên khi sai sót xẩy ra ứng dụng phải đưa tinh trang trơ vê như trươc khi thưc hiện giao dich (roll back) .

Transaction Môt trong các lợi ích chính sư dụng PreparedStatement là thi hành các câu lệnh sql theo kiểu giao dich. Sẽ là tôn thơi gian khi mỗi câu lệnh chương trinh hoàn tất luôn vào trong cơ sơ dữ liệu. Bằng cách set đặt chế đô tư đông hoàn tất(commit) là false, lập trinh viên có thể update cơ sơ dữ liệu và hoàn tất

trọn vẹn giao dich. Cung vậy , mỗi câu lệnh sql phụ thuôc vào các câu lệnh khác, toàn bô giao dich có thể bi đưa trơ lai trang thái

ban đầu như trươc khi giao dich (roll back) và ngươi dùng sẽ được thông báo vê điêu này.

Ví dụ cho Transactions:

Connection connection = null; try {  connection = DriverManager.getConnection(                        "jdbc:oracle:thin:@machinename:15 21:dbname",                                      "username","password");  connection.setAutoCommit(false);  PreparedStatement updateQty =

Page 18: Sử dụng JDBC

  connection.prepareStatement("UPDATE STORE_SALES SET QTY = ?"                            +" WHERE ITEM_CODE = ? ");

-Để bắt đầu môt giao dich (transaction), ban tao môt đôi tượng PreparedStatement như thông thương . -Vơi đôi tượng Connection ban tắt bo đi chế đô tư đông hoàn tất vào database (commit) connection.setAutoCommit(false) . Vi mặc đinh là chế đô commit được set đặt là true .

Ví dụ cho Transaction (tiếp theo)

// Mảng 2 chiều các giá trị  int[][] arrValueToUpdate =                 { {123, 500},                   {124, 250},                   {125, 10},                   {126, 350} }; int iRecordsUpdate = 0; for ( int items=0 ; items < arrValueToUpdate.length ; items++) {    int itemCode = arrValueToUpdate[items][0];    int qty = arrValueToUpdate[items][1];

Ở đây chúng ta tao ra môt mảng 2 chiêu và sẽ dùng mảng này như môt mảng dữ liệu mà chúng ta sẽ phải upload đông loat chúng vào trong cơ sơ dữ liệu cùng môt lần .  

Transaction Example cont.

updateQty.setInt(1,qty);    updateQty.setInt(2,itemCode);    iRecordsUpdate += updateQty.executeUpdate();  }  connection.commit();  System.out.println(iRecordsUpdate + " record(s) have been updated"); } catch(SQLException sqle) {//Nếu có gì đó sai xót sẩy ra khi chạy     System.out.println("" + sqle);

-Sau mỗi lần set đặt giá tri cho đôi tượng PreparedStatement ứng vơi các vi trí dấu ? , chúng ta gọi method executeUpdate() nhưng nó thưc sư chưa tao ra thay đổi trong cơ sơ dữ liệu-Sau vòng lặp chúng ta gọi method commit() để tao ra sư thay đổi đông loat trong cơ sơ dữ liệu .Nếu ban không gọi method này sẽ không có gi thay đổi trong cơ sơ dữ liệu hết .

try {     /* Khi có sai sót xẩy ra gọi method roolback() .Để khôi phục lại      trạng thái của cơ sở dữ liệu như trước khi gọi các lệnh update trên */      connection.rollback();    }catch(SQLException sqleRollback) {      System.out.println("" + sqleRollback);    } } finally {    try {     connection.close();    }catch(SQLException sqleClose) {       System.out.println("" + sqleClose);    } 

-Toàn bô quá trinh sư ly được đặt trong khôi try/catch . Bất kỳ môt sai sót nào trong quá trinh chay update vào cơ sơ dữ liệu sẽ được tóm bơi SQLException , ban sẽ ra lệnh cho chương trinh khôi phục lai trang thái như trươc khi gọi các câu lệnh update . -Cung vậy trong vòng khôi finally ban đóng kết nôi vơi cơ sơ dữ liệu lai .