Java-JDBC學(xué)習(xí)教程-由淺入深
《Java-JDBC學(xué)習(xí)教程-由淺入深》由會(huì)員分享,可在線閱讀,更多相關(guān)《Java-JDBC學(xué)習(xí)教程-由淺入深(98頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
目錄 第一節(jié) 整理目的 3 第二節(jié) jdbc的概念 3 2.1概念 3 2.2 Jdbc與應(yīng)用程序的關(guān)系 3 2.3 數(shù)據(jù)庫(kù)的連接步驟 4 2.4 Quick Start 4 第三節(jié) 如何與數(shù)據(jù)庫(kù)建立連接 6 3.1 注冊(cè)驅(qū)動(dòng) 6 3.2 建立數(shù)據(jù)庫(kù)的連接 8 3.3 規(guī)范Quick Start中的例子 10 第四節(jié) Statement 接口的使用詳解 12 4.1 Statement 的常用方法 12 4.2 CRUD操作 16 4.3 Statement有那些缺點(diǎn) 19 第五節(jié) ResultSet接口的使用詳解 20 第六節(jié) JDBC 中數(shù)據(jù)類(lèi)型詳解 30 6.1 基本數(shù)據(jù)類(lèi)型 30 6.2 日期類(lèi)型 34 6.3 CLOB類(lèi)型 36 6.4 BLOB類(lèi)型 39 6.5 其他數(shù)據(jù)類(lèi)型 41 第七節(jié) DAO設(shè)計(jì)模式詳解 41 7.1 實(shí)際項(xiàng)目中如何使用JDBC 41 7.2 DAO設(shè)計(jì)模式簡(jiǎn)介 42 7.3 DAO設(shè)計(jì)模式的實(shí)現(xiàn) 42 7.4 DAO設(shè)計(jì)模式與工廠模式的整合 49 7.5 DAO設(shè)計(jì)模式測(cè)試 52 第八節(jié) JDBC對(duì)事務(wù)的支持 52 8.1 模擬轉(zhuǎn)賬 53 8.2 jdbc默認(rèn)事務(wù) 54 8.3 事務(wù)提交與回滾 54 8.4 設(shè)置保存點(diǎn) 55 8.5 JTA事務(wù)的介紹 56 8.6 數(shù)據(jù)庫(kù)的隔離級(jí)別介紹 56 8.6.1 未提交讀 57 8.6.2 提交讀 58 8.6.3 重復(fù)讀 59 8.6.4 序列化讀 60 8.7 小結(jié) 62 第九節(jié) PreparedStatement接口的使用 62 第十節(jié) CallableStatement接口的使用 62 9.1 無(wú)參無(wú)返回值存儲(chǔ)過(guò)程調(diào)用 63 9.2 有參無(wú)返回值存儲(chǔ)過(guò)程調(diào)用 63 9.3 有參有返回值存儲(chǔ)過(guò)程調(diào)用 64 9.4 JDBC其他API 65 第十一節(jié) 元數(shù)據(jù)信息 66 11.1 數(shù)據(jù)庫(kù)元數(shù)據(jù)信息 66 11.2 參數(shù)元數(shù)據(jù)信息 67 第十二節(jié) 批處理的使用 67 12.1 普通方式插入一千條數(shù)據(jù) 68 12.2 批處理方式插入一千條數(shù)據(jù) 69 第十三節(jié) JDBC其他API 70 13.1 可滾動(dòng)結(jié)果集 70 13.2 分頁(yè)技術(shù) 72 13.3 可更新結(jié)果集 73 第十四節(jié) 編寫(xiě)一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)連接池 74 14.1 為什么要使用數(shù)據(jù)庫(kù)連接池 74 14.2 數(shù)據(jù)庫(kù)連接池雛形 74 14.2 數(shù)據(jù)庫(kù)連接池優(yōu)化 77 14.2.1 對(duì)線程池加鎖 77 14.2.2 連接不夠用時(shí)拋出異常 77 14.3 數(shù)據(jù)庫(kù)連接池之代理模式 78 14.3.1 靜態(tài)代理 78 14.3.2 動(dòng)態(tài)代理 84 14.4 DBCP數(shù)據(jù)庫(kù)連接池的使用 87 第十五節(jié) jdbc輕量級(jí)封裝 88 15.1 將結(jié)果集封裝為Map 88 15.1.1 ResultSetMetaData演示 88 15.1.2解決多行記錄的問(wèn)題 89 15.1.3 Map結(jié)果集的封裝 90 15.2 將結(jié)果集封裝為對(duì)象 91 15.2.1 user表POJO的編寫(xiě) 91 15.2.2 Bean結(jié)果集的封裝 92 15.3 將結(jié)果集封裝為L(zhǎng)ist 94 15.4 策略模式的應(yīng)用 96 15.4.1 Map結(jié)果集策略模式應(yīng)用 96 15.4.2 Bean結(jié)果集策略模式應(yīng)用 97 15.4.3 List結(jié)果集策略模式應(yīng)用 98 15.4.4 單元測(cè)試 99 15.5 模板模式的應(yīng)用 100 第十六節(jié) 近期推出 101 第一節(jié) 整理目的 當(dāng)今orm等全自動(dòng)針對(duì)對(duì)象持久化的框架越來(lái)越多并且也越來(lái)越成熟(ibatis,hibernate,ejb的jpa),但是無(wú)奈新東家需要使用jdbc(原始手工作坊)的模式和數(shù)據(jù)庫(kù)打交道,用了幾年的ibatis,再次使用jdbc發(fā)現(xiàn)有些細(xì)節(jié)和底層的東西自己并不是十分清楚,所以就啰理啰嗦的整理出一份學(xué)習(xí)筆記,第一作為自己對(duì)jdbc重新的復(fù)習(xí),第二如果有可能希望給初學(xué)jdbc的朋友帶來(lái)一定的便利,這樣也不枉我點(diǎn)點(diǎn)滴滴的記錄。 隨著對(duì)jdbc整理和學(xué)習(xí)的逐漸深入,發(fā)現(xiàn)原先使用orm框架時(shí)忽略了那么多的細(xì)節(jié),這樣在出現(xiàn)問(wèn)題或者學(xué)習(xí)orm更加深入知識(shí)時(shí)則會(huì)顯得力不從心,在本文檔將jdbc如何入門(mén)闡述清楚之后,增加了如下的內(nèi)容: 數(shù)據(jù)庫(kù)連接池,以及常用連接池的使用(dbcp,c3p0等) 編寫(xiě)一套基于jdbc輕量級(jí)的api,方便使用; 如何將查詢(xún)結(jié)果封裝為對(duì)象; 如何將查詢(xún)結(jié)果封裝為Map; 如何將查詢(xún)結(jié)果封裝為L(zhǎng)ist; 如何在JDBC的使用中加入策略,模板等模式; 在后面的JDBC高級(jí)部分將會(huì)講解到Dbutils源碼,Spring對(duì)JDBC的強(qiáng)大封裝 第二節(jié) jdbc的概念 2.1概念 我最不喜歡替別人整理某個(gè)名詞的概念了,只要是概念性的東西基本上在任何地方都可以查得到,所以我就通俗的寫(xiě)一些自己對(duì)jdbc的理解,所謂jdbc就是java與數(shù)據(jù)庫(kù)之間進(jìn)行通訊的api,也就是一個(gè)標(biāo)準(zhǔn),所以如果一個(gè)java應(yīng)用程序想要和數(shù)據(jù)庫(kù)打交道基本上都離不開(kāi)jdbc,眾所周知,一些優(yōu)秀的orm框架的底層也是采用jdbc進(jìn)行封裝的。 2.2 Jdbc與應(yīng)用程序的關(guān)系 JdbcAPI所處的位置和它與應(yīng)用程序之間的關(guān)系,下面的一張圖再也明顯不過(guò)了,其中綠色的部分代表jdbcAPI,它提供了很多接口,并且本身也實(shí)現(xiàn)了很多方法,可以看到藍(lán)色的部分就是各個(gè)數(shù)據(jù)庫(kù)廠商自己對(duì)jdbcAPI的一些實(shí)現(xiàn),這就是我們常見(jiàn)的數(shù)據(jù)庫(kù)連接驅(qū)動(dòng),這是使用jdbc程序進(jìn)行開(kāi)發(fā)必不可少的東西。 2.3 數(shù)據(jù)庫(kù)的連接步驟 1. 注冊(cè)驅(qū)動(dòng) (Driver) 2. 建立連接(創(chuàng)建Connection) 3. 創(chuàng)建執(zhí)行sql語(yǔ)句(通常是創(chuàng)建Statement或者其子類(lèi)) 4. 執(zhí)行語(yǔ)句 5. 處理執(zhí)行結(jié)果(在非查詢(xún)語(yǔ)句中,該步驟是可以省略的) 6. 釋放相關(guān)資源 在后文中,將會(huì)對(duì)上述幾個(gè)步驟一一進(jìn)行講解,希望讀者能夠仔細(xì)閱讀; 2.4 Quick Start 好了,了解了一下jdbc的基本概念,相比對(duì)jdbc已經(jīng)有了一個(gè)感性的認(rèn)識(shí),現(xiàn)在我們?yōu)榱酥庇^期間,直接來(lái)上一段代碼了解一下jdbc最簡(jiǎn)單的程序如何進(jìn)行開(kāi)發(fā)的。 在該小節(jié)中,我們以一個(gè)簡(jiǎn)單的增刪改查為例進(jìn)行說(shuō)明,然后會(huì)將該章節(jié)中涉及的各個(gè)常用以及關(guān)鍵的API進(jìn)行詳細(xì)的講解; 首先我們創(chuàng)建一個(gè)數(shù)據(jù)表,在test數(shù)據(jù)庫(kù)下,見(jiàn)表語(yǔ)句為 create table user(id integer primary key, name varchar(30) , birthday date, money float); 插入兩條語(yǔ)句 l insert into user values(2,zhangsan,2010-01-01,15000); l insert into user values(1,wangwenjun,1984-06-09,8500.00); 好了,數(shù)據(jù)準(zhǔn)備好了,我們通過(guò)一個(gè)完整的例子講上述中數(shù)據(jù)庫(kù)的連接步驟進(jìn)行一個(gè)演示,在本例子中,初學(xué)者可能有些地方會(huì)覺(jué)得陌生,看不明白,不用著急,在后文中會(huì)對(duì)涉及的知識(shí)點(diǎn)逐個(gè)進(jìn)行講解 @Test public void wholeExample(){ try { //1.注冊(cè)驅(qū)動(dòng) Class.forName("com.mysql.jdbc.Driver"); //2.獲取數(shù)據(jù)庫(kù)連接 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); //3.創(chuàng)建執(zhí)行句柄 Statement stmt = conn.createStatement(); //4.執(zhí)行sql語(yǔ)句 ResultSet rs = stmt.executeQuery("select * from user"); //5.處理執(zhí)行結(jié)果 while(rs.next()){ System.out.println("id:"+rs.getInt(1)+"\tname:"+rs.getString(2)+"\tbirthday:"+rs.getDate(3)+"\tmoney:"+rs.getFloat(4)); } //6.釋放資源 rs.close(); stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } 執(zhí)行結(jié)果如下 id:1 name:wangwenjun birthday:1984-06-09 money:8500.0 id:2 name:zhangsan birthday:2010-01-01 money:15000.0 第三節(jié) 如何與數(shù)據(jù)庫(kù)建立連接 3.1 注冊(cè)驅(qū)動(dòng) l 第一種注冊(cè)方式 通常來(lái)說(shuō),注冊(cè)驅(qū)動(dòng)的方式有三種,下面我們將一一進(jìn)行介紹,首先來(lái)看看直接調(diào)用DriverManager的registerDriver方法進(jìn)行加載驅(qū)動(dòng),在本文中所有的程序均是在mysql數(shù)據(jù)庫(kù)上進(jìn)行演示的。 示例代碼如下 @Test public void registDriver1(){ try { DriverManager.registerDriver(new com.mysql.jdbc.Driver()); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } } 執(zhí)行結(jié)果為 可以看到,當(dāng)前我們的程序與數(shù)據(jù)庫(kù)的連接是正常的。 l 第二種注冊(cè)方式 @Test public void registDriver2(){ try { System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } } 執(zhí)行結(jié)果為 可以看到,當(dāng)前我們的程序與數(shù)據(jù)庫(kù)的連接是正常的。 l 第三種注冊(cè)方式 @Test public void registDriver3(){ try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 執(zhí)行結(jié)果為 可以看到,當(dāng)前我們的程序與數(shù)據(jù)庫(kù)的連接是正常的。 一般來(lái)說(shuō)注冊(cè)驅(qū)動(dòng)的方式大致上有上述三個(gè),但是最常用的是最后一個(gè),通過(guò)我們的代碼演示可以看出,數(shù)據(jù)庫(kù)都是完全可以被訪問(wèn)成功的。 3.2 建立數(shù)據(jù)庫(kù)的連接 其實(shí)在上文中的代碼演示中,我們都會(huì)看到如何獲取一個(gè)數(shù)據(jù)庫(kù)連接,就是通過(guò)DriverManager.getConnection()方法獲取數(shù)據(jù)庫(kù)的鏈接,該方法大致有三個(gè)重載的方法,都是可以進(jìn)行數(shù)據(jù)庫(kù)連接的獲取的,下面我們將會(huì)一一進(jìn)行演示 Static Connection getConnection(Stringurl) 試圖建立到給定數(shù)據(jù)庫(kù) URL 的連接。 static Connection getConnection(Stringurl, Propertiesinfo) 試圖建立到給定數(shù)據(jù)庫(kù) URL 的連接。 static Connection getConnection(Stringurl,String user, Stringpassword) 試圖建立到給定數(shù)據(jù)庫(kù) URL 的連接。 l getConnection(Stringurl) 該實(shí)例中,登錄數(shù)據(jù)庫(kù)的所有信息都編寫(xiě)在url中,實(shí)例代碼如下 @Test public void getConn1(){ try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?user=root&password=r66t"); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } l getConnection(Stringurl, Propertiesinfo) 該方法則是將用戶(hù)名和密碼的信息存放在一個(gè)Properties鍵值對(duì)中,示例代碼如下 @Test public void getConn2(){ try { Class.forName("com.mysql.jdbc.Driver"); Properties props = new Properties(); props.put("user", "root"); props.put("password", "r66t"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test",props); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } l getConnection(Stringurl,String user, Stringpassword) 該方法則是我們?cè)谏衔闹醒菔玖撕芏啻蔚姆绞?,也是最常用的一種方式,在這里再次進(jìn)行一下贅述 @Test public void getConn3(){ try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); Assert.assertEquals(false, conn.isClosed()); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 3.3 規(guī)范Quick Start中的例子 其中,我們?cè)赒uick Start中寫(xiě)了一個(gè)較為完整的代碼示例,但是在該代碼中存在很多的問(wèn)題,我們通過(guò)本節(jié)的介紹,一一進(jìn)行規(guī)范和優(yōu)化,并且說(shuō)明一下優(yōu)化的好處是什么 使用數(shù)據(jù)庫(kù)時(shí),涉及數(shù)據(jù)庫(kù)的資源都是非常奇缺的,我們?cè)谑褂玫倪^(guò)程中務(wù)必保證我們將使用過(guò)的資源釋放,供別人再次使用或者自己下次再次使用,還有,創(chuàng)建數(shù)據(jù)庫(kù)連接時(shí)可能存在各種各樣的問(wèn)題導(dǎo)致數(shù)據(jù)庫(kù)連接獲取失敗,這個(gè)時(shí)候你的應(yīng)用應(yīng)該有義務(wù)告知上一層使用者到底出現(xiàn)了什么問(wèn)題,這樣就需要一個(gè)異常傳遞的過(guò)程(異常是一個(gè)比較復(fù)雜的機(jī)制,筆者在另一篇文章中有詳細(xì)的講解,希望讀者能夠關(guān)注) @Test public void regularWhole() throws Exception{//拋出異常 Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //1.注冊(cè)驅(qū)動(dòng) Class.forName("com.mysql.jdbc.Driver"); //2.獲取數(shù)據(jù)庫(kù)連接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","r66t"); //3.創(chuàng)建執(zhí)行句柄 stmt = conn.createStatement(); //4.執(zhí)行sql語(yǔ)句 rs = stmt.executeQuery("select * from user"); //5.處理執(zhí)行結(jié)果 while(rs.next()){ System.out.println("id:"+rs.getInt(1)+"\tname:"+rs.getString(2)+"\tbirthday:"+rs.getDate(3)+"\tmoney:"+rs.getFloat(4)); } } finally{ try { //6.釋放資源 if(null!=rs){ rs.close(); } if(null!=stmt){ stmt.close(); } if(null!=conn){ conn.close(); } } finally{ if(null!=rs){ rs.close(); } if(null!=stmt){ stmt.close(); } if(null!=conn){ conn.close(); } } } } 在該實(shí)例中,可以看出確保了資源的完全釋放,也將異常拋出告知上一層使用者,那塊出現(xiàn)了問(wèn)題,但是可以看到代碼明顯寫(xiě)的很羅嗦,而且有很多地方還是值得考究的 其中,注冊(cè)驅(qū)動(dòng),數(shù)據(jù)庫(kù)的驅(qū)動(dòng)注冊(cè),只需要一次即可,重復(fù)注冊(cè)是沒(méi)有任何意義的,并且資源的釋放,在每次使用的時(shí)候都進(jìn)行資源的釋放(寫(xiě)資源釋放的代碼)顯得非常羅嗦,所以我們進(jìn)行再一次的一個(gè)優(yōu)化,代碼如下 package com.wangwenjun.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public final class ConnCreate { static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection(String url, String user, String pwd) { Connection conn = null; try { conn = DriverManager.getConnection(url, user, pwd); } catch (SQLException e) { e.printStackTrace(); } return conn; } public static void close(Connection conn, Statement stmt, ResultSet rs) throws SQLException { if (null != rs) { rs.close(); } if (null != stmt) { stmt.close(); } if (null != conn) { conn.close(); } } } 可以看出,驅(qū)動(dòng)只會(huì)被注冊(cè)一次,并且對(duì)資源釋放的代碼進(jìn)行了抽取,在以后的使用過(guò)程中則會(huì)簡(jiǎn)單許多,當(dāng)然上述的代碼如果還需要追究問(wèn)題,肯定還是存在的,在接下來(lái)的章節(jié)中我們也會(huì)進(jìn)行深入的說(shuō)明。 第四節(jié) Statement 接口的使用詳解 Statement 是應(yīng)用與數(shù)據(jù)庫(kù)打交道最關(guān)鍵的一個(gè)接口,該接口包括了我們常用的CRUD操作,還可以設(shè)置抓取策略,比如設(shè)置數(shù)據(jù)庫(kù)的游標(biāo)是多少,可以根據(jù)數(shù)據(jù)量進(jìn)行調(diào)優(yōu),也可以進(jìn)行批量處理等,總之,該接口是非常關(guān)鍵的一個(gè)接口,包括后文中的預(yù)處理命令接口以及執(zhí)行存儲(chǔ)過(guò)程的接口。 4.1 Statement 的常用方法 下面的列表是從jdk API文檔上粘貼出來(lái)的,當(dāng)然很多方法我們并不是都能碰到,但是了解一下還是會(huì)有好處的 方法摘要 void addBatch(Stringsql) 將給定的 SQL 命令添加到此 Statement 對(duì)象的當(dāng)前命令列表中。 void cancel() 如果 DBMS 和驅(qū)動(dòng)程序都支持中止 SQL 語(yǔ)句,則取消此 Statement 對(duì)象。 void clearBatch() 清空此 Statement 對(duì)象的當(dāng)前 SQL 命令列表。 void clearWarnings() 清除在此 Statement 對(duì)象上報(bào)告的所有警告。 void close() 立即釋放此 Statement 對(duì)象的數(shù)據(jù)庫(kù)和 JDBC 資源,而不是等待該對(duì)象自動(dòng)關(guān)閉時(shí)發(fā)生此操作。 boolean execute(Stringsql) 執(zhí)行給定的 SQL 語(yǔ)句,該語(yǔ)句可能返回多個(gè)結(jié)果。 boolean execute(Stringsql, intautoGeneratedKeys) 執(zhí)行給定的 SQL 語(yǔ)句(該語(yǔ)句可能返回多個(gè)結(jié)果),并通知驅(qū)動(dòng)程序所有自動(dòng)生成的鍵都應(yīng)該可用于檢索。 boolean execute(Stringsql, int[]columnIndexes) 執(zhí)行給定的 SQL 語(yǔ)句(該語(yǔ)句可能返回多個(gè)結(jié)果),并通知驅(qū)動(dòng)程序在給定數(shù)組中指示的自動(dòng)生成的鍵應(yīng)該可用于檢索。 boolean execute(Stringsql, String[]columnNames) 執(zhí)行給定的 SQL 語(yǔ)句(該語(yǔ)句可能返回多個(gè)結(jié)果),并通知驅(qū)動(dòng)程序在給定數(shù)組中指示的自動(dòng)生成的鍵應(yīng)該可用于檢索。 int[] executeBatch() 將一批命令提交給數(shù)據(jù)庫(kù)來(lái)執(zhí)行,如果全部命令執(zhí)行成功,則返回更新計(jì)數(shù)組成的數(shù)組。 ResultSet executeQuery(Stringsql) 執(zhí)行給定的 SQL 語(yǔ)句,該語(yǔ)句返回單個(gè) ResultSet 對(duì)象。 int executeUpdate(Stringsql) 執(zhí)行給定 SQL 語(yǔ)句,該語(yǔ)句可能為 INSERT、UPDATE 或 DELETE 語(yǔ)句,或者不返回任何內(nèi)容的 SQL 語(yǔ)句(如 SQL DDL 語(yǔ)句)。 int executeUpdate(Stringsql, intautoGeneratedKeys) 執(zhí)行給定的 SQL 語(yǔ)句,并用給定標(biāo)志通知驅(qū)動(dòng)程序由此 Statement 生成的自動(dòng)生成鍵是否可用于檢索。 int executeUpdate(Stringsql, int[]columnIndexes) 執(zhí)行給定的 SQL 語(yǔ)句,并通知驅(qū)動(dòng)程序在給定數(shù)組中指示的自動(dòng)生成的鍵應(yīng)該可用于檢索。 int executeUpdate(Stringsql, String[]columnNames) 執(zhí)行給定的 SQL 語(yǔ)句,并通知驅(qū)動(dòng)程序在給定數(shù)組中指示的自動(dòng)生成的鍵應(yīng)該可用于檢索。 Connection getConnection() 檢索生成此 Statement 對(duì)象的 Connection 對(duì)象。 int getFetchDirection() 檢索從數(shù)據(jù)庫(kù)表獲取行的方向,該方向是根據(jù)此 Statement 對(duì)象生成的結(jié)果集合的默認(rèn)值。 int getFetchSize() 檢索結(jié)果集合的行數(shù),該數(shù)是根據(jù)此 Statement 對(duì)象生成的 ResultSet 對(duì)象的默認(rèn)獲取大小。 ResultSet getGeneratedKeys() 檢索由于執(zhí)行此 Statement 對(duì)象而創(chuàng)建的所有自動(dòng)生成的鍵。 int getMaxFieldSize() 檢索可以為此 Statement 對(duì)象所生成 ResultSet 對(duì)象中的字符和二進(jìn)制列值返回的最大字節(jié)數(shù)。 int getMaxRows() 檢索由此 Statement 對(duì)象生成的 ResultSet 對(duì)象可以包含的最大行數(shù)。 boolean getMoreResults() 移動(dòng)到此 Statement 對(duì)象的下一個(gè)結(jié)果,如果其為 ResultSet 對(duì)象,則返回 true,并隱式關(guān)閉利用方法 getResultSet 獲取的所有當(dāng)前 ResultSet 對(duì)象。 boolean getMoreResults(intcurrent) 將此 Statement 對(duì)象移動(dòng)到下一個(gè)結(jié)果,根據(jù)給定標(biāo)志指定的指令處理所有當(dāng)前 ResultSet 對(duì)象;如果下一個(gè)結(jié)果為 ResultSet 對(duì)象,則返回 true。 int getQueryTimeout() 檢索驅(qū)動(dòng)程序等待 Statement 對(duì)象執(zhí)行的秒數(shù)。 ResultSet getResultSet() 以 ResultSet 對(duì)象的形式檢索當(dāng)前結(jié)果。 int getResultSetConcurrency() 檢索此 Statement 對(duì)象生成的 ResultSet 對(duì)象的結(jié)果集合并發(fā)性。 int getResultSetHoldability() 檢索此 Statement 對(duì)象生成的 ResultSet 對(duì)象的結(jié)果集合可保存性。 int getResultSetType() 檢索此 Statement 對(duì)象生成的 ResultSet 對(duì)象的結(jié)果集合類(lèi)型。 int getUpdateCount() 以更新計(jì)數(shù)的形式檢索當(dāng)前結(jié)果;如果結(jié)果為 ResultSet 對(duì)象或沒(méi)有更多結(jié)果,則返回 -1。 SQLWarning getWarnings() 檢索此 Statement 對(duì)象上的調(diào)用報(bào)告的第一個(gè)警告。 void setCursorName(Stringname) 將 SQL 指針名稱(chēng)設(shè)置為給定的 String,后續(xù) Statement 對(duì)象的 execute 方法將使用此字符串。 void setEscapeProcessing(booleanenable) 將轉(zhuǎn)義處理設(shè)置為開(kāi)或關(guān)。 void setFetchDirection(intdirection) 向驅(qū)動(dòng)程序提供關(guān)于方向的提示,在使用此 Statement 對(duì)象創(chuàng)建的 ResultSet 對(duì)象中將按該方向處理行。 void setFetchSize(introws) 為 JDBC 驅(qū)動(dòng)程序提供關(guān)于需要更多行時(shí)應(yīng)該從數(shù)據(jù)庫(kù)獲取的行數(shù)的提示。 void setMaxFieldSize(intmax) 設(shè)置將字符或二進(jìn)制值存儲(chǔ)到給定字節(jié)數(shù)中 ResultSet 列中的最大字節(jié)數(shù)限制。 void setMaxRows(intmax) 將任何 ResultSet 對(duì)象都可以包含的最大行數(shù)限制設(shè)置為給定數(shù)。 void setQueryTimeout(intseconds) 將驅(qū)動(dòng)程序等待 Statement 對(duì)象執(zhí)行的秒數(shù)設(shè)置為給定秒數(shù)。 其中API 上特別注明了一句話(huà),是非常關(guān)鍵的,我們?cè)谑褂玫臅r(shí)候一定要注意,否則會(huì)出現(xiàn)很?chē)?yán)重的問(wèn)題 在默認(rèn)情況下,同一時(shí)間每個(gè) Statement 對(duì)象在只能打開(kāi)一個(gè) ResultSet 對(duì)象。因此,如果讀取一個(gè) ResultSet 對(duì)象與讀取另一個(gè)交叉,則這兩個(gè)對(duì)象必須是由不同的 Statement 對(duì)象生成的。如果存在某個(gè)語(yǔ)句的打開(kāi)的當(dāng)前 ResultSet 對(duì)象,則 Statement 接口中的所有執(zhí)行方法都會(huì)隱式關(guān)閉它。 其實(shí)從Statement的原理來(lái)說(shuō),底層他還是從過(guò)游標(biāo)的方式操作數(shù)據(jù),尤其是進(jìn)行查詢(xún)的時(shí)候,并且還是顯式游標(biāo),如果對(duì)其不能進(jìn)行及時(shí)的資源釋放,當(dāng)運(yùn)行到一定時(shí)間,數(shù)據(jù)庫(kù)則會(huì)拋出異常給應(yīng)用(打開(kāi)的游標(biāo)超過(guò)了最大值) 4.2 CRUD操作 我們還是通過(guò)上述創(chuàng)建的user表進(jìn)行一下增刪改查的操作,來(lái)看看通過(guò)Statement怎樣進(jìn)行數(shù)據(jù)的操作。 l 新增數(shù)據(jù) 現(xiàn)在想到數(shù)據(jù)庫(kù)中新增一條數(shù)據(jù),編號(hào)為3,名稱(chēng)為lisi,生日為2010-05-05,money為13000.00,代碼示例如下 @Test public void insert() throws SQLException{ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 1.注冊(cè)驅(qū)動(dòng) //Class.forName("com.mysql.jdbc.Driver"); // 2.獲取數(shù)據(jù)庫(kù)連接 conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test", "root", "r66t"); // 3.創(chuàng)建執(zhí)行句柄 stmt = conn.createStatement(); // 4.執(zhí)行sql語(yǔ)句 String sql="insert into user(id,name,birthday,money) values(3,lisi,2010-05-05,13000.00)"; stmt.executeUpdate(sql); } finally { ConnCreate.close(conn,stmt,rs); } } 執(zhí)行結(jié)果對(duì)比為(下圖為,sql執(zhí)行前后的查詢(xún)展示) l 修改數(shù)據(jù) 物價(jià)上漲,待遇一直不漲,所以我們將lisi的money給再加上5000元,當(dāng)然這只是一個(gè)演示,意思就是說(shuō)更新一下數(shù)據(jù)表中的數(shù)據(jù),如果真的可以這么做,大家可以隨時(shí)Q我,給增加工資,呵呵,好了,直接上演示代碼 @Test public void update() throws SQLException{ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 1.注冊(cè)驅(qū)動(dòng) //Class.forName("com.mysql.jdbc.Driver"); // 2.獲取數(shù)據(jù)庫(kù)連接 conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test", "root", "r66t"); // 3.創(chuàng)建執(zhí)行句柄 stmt = conn.createStatement(); // 4.執(zhí)行sql語(yǔ)句 String sql="update user set money=money+5000 where id=3"; stmt.executeUpdate(sql); } finally { ConnCreate.close(conn,stmt,rs); } } 執(zhí)行結(jié)果為 可以看出,lisi的money字段被更新了 l 刪除數(shù)據(jù) 剛才將lisi的money給上調(diào)了,結(jié)果被領(lǐng)導(dǎo)發(fā)現(xiàn)了,現(xiàn)在要求將lisi給開(kāi)除了,所以我們只好進(jìn)行刪除操作了(所以說(shuō)敏感數(shù)據(jù)不能隨便修改噠),示例代碼如下 @Test public void delete() throws SQLException{ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 1.注冊(cè)驅(qū)動(dòng) //Class.forName("com.mysql.jdbc.Driver"); // 2.獲取數(shù)據(jù)庫(kù)連接 conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test", "root", "r66t"); // 3.創(chuàng)建執(zhí)行句柄 stmt = conn.createStatement(); // 4.執(zhí)行sql語(yǔ)句 String sql="delete from user where id=3"; stmt.executeUpdate(sql); } finally { ConnCreate.close(conn,stmt,rs); } } 執(zhí)行結(jié)果如下圖所示 從上圖可以看出,lisi已經(jīng)被刪除掉了。 l 查詢(xún)數(shù)據(jù) 前面的章節(jié)中,關(guān)于查詢(xún)的示例實(shí)在太多了,此處省略。 4.3 Statement有那些缺點(diǎn) 應(yīng)用執(zhí)行sql其實(shí)大體上可以分為兩步,第一步是將sql交給數(shù)據(jù)庫(kù)應(yīng)用檢查編譯,然后再由數(shù)據(jù)庫(kù)將執(zhí)行結(jié)果返回給應(yīng)用。好了我們看一個(gè)實(shí)例,來(lái)感受一下Statement會(huì)有哪些缺點(diǎn) @Test public void conditionQuery() throws SQLException{ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 1.注冊(cè)驅(qū)動(dòng) //Class.forName("com.mysql.jdbc.Driver"); // 2.獲取數(shù)據(jù)庫(kù)連接 conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test", "root", "r66t"); // 3.創(chuàng)建執(zhí)行句柄 stmt = conn.createStatement(); // 4.執(zhí)行sql語(yǔ)句 String sql="select * from user where name=wangwenjun or 1 or "; System.out.println(sql); rs = stmt.executeQuery(sql); // 5.處理執(zhí)行結(jié)果 while (rs.next()) { System.out.println("id:" + rs.getInt(1) + "\tname:" + rs.getString(2) + "\tbirthday:" + rs.getDate(3) + "\tmoney:" + rs.getFloat(4)); } } finally { ConnCreate.close(conn,stmt,rs); } } 請(qǐng)看一下我們的代碼,其中name的值很詭異,假設(shè),這個(gè)值是由前臺(tái)用戶(hù)傳遞進(jìn)來(lái)的,我們就不能保證他到底是什么,當(dāng)然我們也可以通過(guò)編寫(xiě)過(guò)濾器來(lái)進(jìn)行規(guī)避,但是我們?cè)趺礃油ㄟ^(guò)jdbc來(lái)規(guī)避上述的問(wèn)題呢,首先看看運(yùn)行結(jié)果吧 select * from user where name=wangwenjun or 1 or id:1 name:wangwenjun birthday:1984-06-09 money:8500.0 id:2 name:zhangsan birthday:2010-01-01 money:15000.0 id:3 name:lisi birthday:2010-05-05 money:18000.0 可以看到將所有的語(yǔ)句都查詢(xún)出來(lái)了。 簡(jiǎn)單總結(jié)一下Statement的缺點(diǎn)哈(純屬個(gè)人觀點(diǎn),可能有些不太全面) l 執(zhí)行時(shí)發(fā)送sql,影響效率. l 同樣的sql,每次都要發(fā)送,不能進(jìn)行有效的緩存,是一種資源的浪費(fèi). l 示例代碼中演示可以看出,為了防止惡意數(shù)據(jù)我們還需要編寫(xiě)附加的程序(過(guò)濾器)帶來(lái)不必要的開(kāi)支. l 拼接sql字符串很容易出現(xiàn)錯(cuò)誤. 為了解決上述的問(wèn)題,我們引入一個(gè)新的接口PreparedStatement,該接口是Statement的子接口,他們的主要區(qū)別是,在執(zhí)行sql之前首先準(zhǔn)備好sql語(yǔ)句,將其中的條件通過(guò)?進(jìn)行占位,還有一個(gè)好處就是,同樣的sql會(huì)被PreparedStatement有效的緩存,也就是說(shuō),數(shù)據(jù)庫(kù)會(huì)減少校驗(yàn)的過(guò)程,減少消耗,這就是我們常說(shuō)的預(yù)處理命令方式,在后文中也會(huì)涉及到。 第五節(jié) ResultSet接口的使用詳解 從字面意思上來(lái)了解,該接口是一個(gè)數(shù)據(jù)集合,是從數(shù)據(jù)庫(kù)中獲取的數(shù)據(jù)會(huì)存放在該集合當(dāng)中,該集合提供了很多種數(shù)據(jù)獲取的方法,詳細(xì)信息,請(qǐng)看下表展示 方法摘要 boolean absolute(introw) 將指針移動(dòng)到此 ResultSet 對(duì)象的給定行編號(hào)。 void afterLast() 將指針移動(dòng)到此 ResultSet 對(duì)象的末尾,正好位于最后一行之后。 void beforeFirst() 將指針移動(dòng)到此 ResultSet 對(duì)象的開(kāi)頭,正好位于第一行之前。 void cancelRowUpdates() 取消對(duì) ResultSet 對(duì)象中的當(dāng)前行所作的更新。 void clearWarnings() 清除在此 ResultSet 對(duì)象上報(bào)告的所有警告。 void close() 立即釋放此 ResultSet 對(duì)象的數(shù)據(jù)庫(kù)和 JDBC 資源,而不是等待該對(duì)象自動(dòng)關(guān)閉時(shí)發(fā)生此操作。 void deleteRow() 從此 ResultSet 對(duì)象和底層數(shù)據(jù)庫(kù)中刪除當(dāng)前行。 int findColumn(StringcolumnName) 將給定的 ResultSet 列名稱(chēng)映射到其 ResultSet 列索引。 boolean first() 將指針移動(dòng)到此 ResultSet 對(duì)象的第一行。 Array getArray(inti) 以 Java 編程語(yǔ)言中 Array 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Array getArray(StringcolName) 以 Java 編程語(yǔ)言中 Array 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 InputStream getAsciiStream(intcolumnIndex) 以 ASCII 字符流的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 InputStream getAsciiStream(StringcolumnName) 以 ASCII 字符流的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 BigDecimal getBigDecimal(intcolumnIndex) 以具有全精度的 java.math.BigDecimal 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 BigDecimal getBigDecimal(intcolumnIndex, intscale) 已過(guò)時(shí)。 BigDecimal getBigDecimal(StringcolumnName) 以具有全精度的 java.math.BigDecimal 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 BigDecimal getBigDecimal(StringcolumnName, intscale) 已過(guò)時(shí)。 InputStream getBinaryStream(intcolumnIndex) 以未解釋字節(jié)的二進(jìn)制流的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 InputStream getBinaryStream(StringcolumnName) 以未解釋的 byte 流的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Blob getBlob(inti) 以 Java 編程語(yǔ)言中 Blob 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Blob getBlob(StringcolName) 以 Java 編程語(yǔ)言中 Blob 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 boolean getBoolean(intcolumnIndex) 以 Java 編程語(yǔ)言中 boolean 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 boolean getBoolean(StringcolumnName) 以 Java 編程語(yǔ)言中 boolean 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 byte getByte(intcolumnIndex) 以 Java 編程語(yǔ)言中 byte 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 byte getByte(StringcolumnName) 以 Java 編程語(yǔ)言中 byte 的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 byte[] getBytes(intcolumnIndex) 以 Java 編程語(yǔ)言中 byte 數(shù)組的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 byte[] getBytes(StringcolumnName) 以 Java 編程語(yǔ)言中 byte 數(shù)組的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Reader getCharacterStream(intcolumnIndex) 以 java.io.Reader 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Reader getCharacterStream(StringcolumnName) 以 java.io.Reader 對(duì)象的形式檢索此 ResultSet 對(duì)象的當(dāng)前行中指定列的值。 Clob getClob(inti) 以 Java- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
15 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開(kāi)word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- Java JDBC 學(xué)習(xí) 教程 由淺入深
鏈接地址:http://m.jqnhouse.com/p-10795933.html