Oracle數據庫部分終于在昨天結束了,整理學習日志到很晚。今天繼續講解JDBC,是方老師授課的。方老師在我們班還有六堂的課程,多少有些舍不得,他是個好老師。學完這六堂課,JAVAWEB基礎到此也就結束了(09-12-18)。十分渴望快些學習到項目那,把這些技術混合運用,做出個像模像樣的東西來!
今天的內容依然很多,我還是好好把它整理出來吧!
一、JDBC中調用Oracle存儲過程:
例,在Oracle中創建一個存儲過程:
CREATE OR REPLACE PROCEDURE UPEMPFUN( ARG_EMPNO IN NUMBER, ARG_SAL IN NUMBER, ARG_RES OUT VARCHAR )IS BEGIN UPDATE EMP SET SAL = ARG_SAL WHERE EMPNO=ARG_EMPNO; COMMIT; ARG_RES := 'OK!'; END; |
在JDBC中,調用上面的存儲過程(我的Oralce出問題了,沒有測試):
CallableStatement cStmt = conn.prepareCall("{call UPEMPFUN(?, ?, ?)}"); // 注冊接收返回值的變量 cStmt.registerOutParameter(3, Types.VARCHAR); cStmt.setInt(1, 7360); cStmt.setFloat(1, 8888); cStmt.execute(); // 打印返回值 System.out.println(cStmt.getString(3)); |
二、JDBC數據庫中的分布技術:
1.ResultSet提供了對結果集進行滾動的功能:
next():移動到下一行
Previous():移動到前一行
absolute(int row):移動到指定行
beforeFirst():移動resultSet的最前面
afterLast() :移動到resultSet的最后面
使用上面的滾動記錄功能可以實現分頁功能,但建議不要使用這種技術進行分頁。因為當記錄數量大的時間,會帶來性能上的下降,資源的浪費。
2.MySQL分頁語句:
Select * from tab_ame limit M,N;
M:記錄起始索引位置
N:獲取記錄數量
3.Oracle分頁語句(TOP-N技術):
Select * from (
Select rownum rn,* from (
Select * from tab_name where 條件
) where rownum <=結束位置
)where rn >=起始位置
它與MySql分頁相比,MySql更方便些。而且MySql中的N直接獲取記錄數量,但Oracle中卻是結束位置的索引和起始位置的索引之間的記錄。
4.編寫一個WEB應用,使用分布技術顯示數據庫中的記錄:
簡易流程圖:(如果看不到圖片,請到這里:http://m.tkk7.com/changcheng/)

ListStudent.java,doGet部分:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取總記錄數量 StudentDao sd = new StudentDao(); int totalrecord = 0; int pagenum = 0; Page page = null; try { totalrecord = sd.getTotal(); // 獲取記錄信息 String currage = request.getParameter("currpage"); page = new Page(totalrecord, (currage != null) ? Integer .parseInt(currage) : 1); page.setRecord(sd.getRecord(page.getStartindex(), page.getPagesize())); } catch (Exception e) { e.printStackTrace(); } // 將信息發往index.jsp進行顯示 request.setAttribute("page", page); request.getRequestDispatcher("index.jsp").forward(request, response); } |
Student.java:
public class StudentDao { // 獲取學生總數 public int getTotal() throws SQLException { // 獲取連接 Connection conn = JdbcUtil.getDataSource().getConnection(); // 查詢數量 PreparedStatement ps = conn .prepareStatement("select count(*) from student"); ResultSet rs = ps.executeQuery(); int total = 0; while (rs.next()) { total = rs.getInt(1); } // 釋放連接 JdbcUtil.release(rs, ps, conn); return total; } // 獲取記錄 public List getRecord(int startindex, int count) throws SQLException { // 獲取連接 Connection conn = JdbcUtil.getDataSource().getConnection(); // 查詢記錄 PreparedStatement ps = conn .prepareStatement("select id,name,sex from student limit ?,?;"); ps.setInt(1, startindex); ps.setInt(2, count); ResultSet rs = ps.executeQuery(); // 讀取記錄 List result = new ArrayList(); while (rs.next()) { StudentBean stuben = new StudentBean(); stuben.setId(rs.getInt("id")); stuben.setName(rs.getString("name")); stuben.setSex(rs.getBoolean("sex")); result.add(stuben); } // 釋放連接 JdbcUtil.release(rs, ps, conn); return result; } } |
Page.java:
public class Page { private int totalrecord;// 總記錄數 private int totalpage;// 總頁面數 private int pagesize = 3;// 頁面顯示記錄數 private int startindex;// 起始索引 private int currpage;// 當前頁面 private List record;// 記錄 public Page(int totalrecord, int currpage) { this.totalrecord = totalrecord; this.currpage = currpage; } public int getTotalrecord() { return this.totalrecord; } public List getRecord() { return record; } public void setRecord(List record) { this.record = record; } // 計算總頁面數 public int getTotalpage() { if (this.totalrecord % this.pagesize == 0) totalpage = this.totalrecord / this.pagesize; else totalpage = this.totalrecord / this.pagesize + 1; return this.totalpage; } // 計算起始索引 public int getStartindex() { this.startindex = (this.currpage - 1) * this.pagesize; return this.startindex; } public int getPagesize() { return this.pagesize; } } |
Index.jsp,body部分:
<body> HI <hr> <table border="1"> <tr> <td>ID</td><td>姓名</td><td>性別</td> </tr> <!-- 顯示記錄信息 --> <cc:forEach var="record" items="${page.record}"> <tr> <td>${record.id }</td><td>${record.name }</td><td>${record.sex }</td> </tr> </cc:forEach> <!-- 顯示翻頁信息 --> </table> <cc:forEach var="i" begin="1" end="${page.totalpage}"> <a href="http://localhost:8080/091210/ListStudent?currpage=${i}">${i}</a> </cc:forEach> </body> |
如果連接的是Oracle數據庫,則使用Oracle數據庫的TOP-N技術即可!
三、JDBC對數據庫LOB操作:
LOB數據(LargeObject),簡稱大對象。它分為兩類:
1. CLOB:CharactorLargeObject,專門用于處理字符的大對象。
2. BLOB:ByteLargeObject,專門用于處理二進制數據,比如圖片等。
1. MySQL中的LOB操作:
在MySQL中:TEXT與CLOB對應,BLOB與BLOB對應。
調用下面的方法設置TEXT:
PreparedStatement.setCharacterStream(index, reader, length); //注意length長度須設置,并且設置為int型 |
調用下面的方法獲取TEXT:
1.reader = resultSet. getCharacterStream(i); 2.reader = resultSet.getClob(i).getCharacterStream(); 3.string = resultSet.getString(i); |
調用下面的方法設置BLOB:
PreparedStatement.setBinaryStream(i, inputStream, length); |
調用下面的方法獲取BLOB:
1.InputStream in = resultSet.getBinaryStream(i); 2.InputStream in = resultSet.getBlob(i).getBinaryStream(); |
在MySql數據庫中使用LOB字段,直接定義這個字段的類型為“TEXT”或“BLOB”即可!
2. Oracle中的LOB操作:
在Oracle中CLOB與“EMPTY_CLOB()”對應,“BLOB”與“EMPTY_BLOB()”對應。
Oracle中設置和獲取BLOB的JDBC方法與MySQL相同。
在Oralce中添加LOB字段插入內容時,必須在事件中進行否則極可能出錯。
注意:在Oracle數據庫中添加CLOB字段必須使用“empty_clob()”,添加BLOB字段必須使用“empty_blob()”。在對他們進行賦值時,必須使用查詢語句獲取對應字段名的指針。在獲取字段指針的查詢語句結尾必須使用“fro update”這樣鎖定該行,保證不會發生沖突。
例,向Oracle數據庫寫入大文本操作:
private static void save() throws Exception { // 獲取連接 Connection conn = JdbcUtil.getDataSource().getConnection(); conn.setAutoCommit(false); PreparedStatement ps = conn .prepareStatement("insert into ocolb(id, text) values (1,empty_clob())"); ps.executeUpdate(); // 獲取指針 ps = conn.prepareStatement("select text from ocolb where id=1 for update;"); ResultSet rs = ps.executeQuery(); // 寫入數據 File imfi = new File("C:/ocolb.txt"); Reader reader = new FileReader(imfi); //ps.setCharacterStream(1, reader, imfi.length()); CLOB clob = (CLOB) rs.getClob("text"); Writer writer = clob.getCharacterOutputStream(); char[] buf = new char[1024]; int len = 0; while((len = reader.read(buf)) != -1){ writer.write(buf, 0, len); } reader.close(); writer.close(); // 提交 conn.commit(); // 釋放連接 JdbcUtil.release(rs, ps, conn); } |
四、JDBC對數據庫批量操作:
當我們向數據庫的一個表中插入100條記錄時,比如向employee表中插入100名員工。難道我們要一條條語句執行?如果插入100萬條呢?后果可想而知,所以需要批量操作來完成此任務。
在JDBC中有兩種方法可以進行指操作:
1. Statement.addBatch(sql):
實現批處理的缺點:當向表中使用sql語句批量插入數據時,采用此種方式需重復寫上多條語句相同,只參數不同的sql語句,工作量大,可讀性差。
String sql1 = "insert into employee(id,name) values(1,'aaa')"; String sql2 = "insert into employee(id,name) values(2,'bbb')"; st = conn.createStatement(); st.addBatch(sql1); st.addBatch(sql2); st.executeBatch(); |
2. PreparedStatement. addBatch():
SQL語句相同,但參數相同。此種方法主要用于在同一個表中批量插入數據、或批量更新數據。
String sql2 = "insert into employee(name,department_id) values(?,?)"; ps = conn.prepareStatement(sql2); Iterator it = department.getEmployees().iterator(); while(it.hasNext()){ Employee e = (Employee) it.next(); ps.setString(1, e.getName()); ps.setInt(2, id); ps.addBatch(); } |
五、JDBC操作多個實體:
操作多個實體?這個玩法第一次聽說。說直白些就是將JAVA對象與數據庫的表,關聯起來。如何關聯?當然是通過代碼關聯了。
例:
1.創建department和employee表:
Create table department( id int primary key auto_increment, name varchar(50) ) Create table employee( id int primary key auto_increment, name varchar(30), department_id int, constraint for_ke foreign key(department_id) references department(id) ) |
2.定義Department和Employee類:
public class Department { private int id; private String name; private Set<Employee> employees = new HashSet<Employee>(); … } public class Employee { private int id; private String name; private Department department; … } |
3.創建一個多Department對象,創建多個個Employee對象,添加到Department對象的SET中。
4.定義一個工具類,將Department對象給工具類的SAVE方法,SAVE方法使用批量操作,將數據添加到數據庫的department和employee表中。
注意:
JAVA里邊無論對象和對象之間什么關系,反應到數據庫中就是外鍵關聯。
在應用設計中盡量不要使用一對多的關系或多對多關系,而是使用多對一的關系。
整理日志比較辛苦,加油!