Java-Web程序設計與案例教程-第6章-數(shù)據(jù)庫整合開發(fā)課件_第1頁
Java-Web程序設計與案例教程-第6章-數(shù)據(jù)庫整合開發(fā)課件_第2頁
Java-Web程序設計與案例教程-第6章-數(shù)據(jù)庫整合開發(fā)課件_第3頁
Java-Web程序設計與案例教程-第6章-數(shù)據(jù)庫整合開發(fā)課件_第4頁
Java-Web程序設計與案例教程-第6章-數(shù)據(jù)庫整合開發(fā)課件_第5頁
已閱讀5頁,還剩113頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第6章數(shù)據(jù)庫整合開發(fā)

第6章數(shù)據(jù)庫整合開發(fā)本章內容MySQL簡介

JDBC概述數(shù)據(jù)庫連接池

DBUtils框架簡介簡易購物商城本章內容MySQL簡介6.1MySQL簡介MySQL是一個關系型數(shù)據(jù)庫,它由瑞典MySQLAB公司開發(fā),目前屬于Oracle旗下的產品。MySQL是最流行的關系型數(shù)據(jù)庫管理系統(tǒng)之一,在Web應用方面,MySQL是最好的關系數(shù)據(jù)庫管理系統(tǒng)(RelationalDataBaseManagementSystem,RDBMS)應用軟件。6.1MySQL簡介MySQL是一個關系型數(shù)據(jù)庫,它由瑞6.2

JDBC概述Java數(shù)據(jù)庫連接技術(JavaDataBaseConnectivity,JDBC)是Java訪問數(shù)據(jù)庫資源的標準,JDBC標準定義了一組JavaAPI,允許用戶寫出SQL語句,然后交給數(shù)據(jù)庫。6.2JDBC概述Java數(shù)據(jù)庫連接技術(JavaD6.2

JDBC概述如圖6.1所示,如果沒有JDBC或者ODBC,開發(fā)人員必須使用不同的一組API來訪問不同的數(shù)據(jù)庫;而有了JDBC或者ODBC,則只需要使用一組API,再加上數(shù)據(jù)庫廠商提供的數(shù)據(jù)庫驅動程序就可以訪問不同的數(shù)據(jù)庫了,如圖6.2所示。所以,利用JDBC,我們就可以把同一個企業(yè)級Java應用移植到另一個數(shù)據(jù)庫應用上。6.2JDBC概述如圖6.1所示,如果沒有JDBC或6.2

JDBC概述圖6.1應用程序直接訪問數(shù)據(jù)庫圖6.2應用程序訪問JDBC6.2JDBC概述圖6.1應用程序直接訪問數(shù)據(jù)庫圖6.6.2

JDBC概述JDBC主要包含兩部分:面向Java程序員的JDBCAPI和面向數(shù)據(jù)庫廠商的JDBCDriveAPI。1.面向Java程序員的JDBCAPI它主要由一系列的接口定義所構成。java.sql.DriveManager:該接口定義了用來處理裝載驅動的程序,并且為創(chuàng)建新的數(shù)據(jù)庫連接提供支持。java.sql.Connection:該接口定義了實現(xiàn)對某一種指定數(shù)據(jù)庫連接的功能。6.2JDBC概述JDBC主要包含兩部分:面向Java程6.2

JDBC概述java.sql.Statement:該接口定義了在一個給定的連接中作為SQL語句執(zhí)行聲明的容器以實現(xiàn)對數(shù)據(jù)庫的操作。它主要包含有如下兩種子類型。java.sql.PreparedStatement:該接口定義了用于執(zhí)行帶或不帶IN參數(shù)的預編譯SQL語句。java.sql.CallableStatement:該接口定義了用于執(zhí)行數(shù)據(jù)庫的存儲過程的調用。java.sql.ResultSet:該接口定義了執(zhí)行數(shù)據(jù)庫的操作后返回的結果集。2.面向數(shù)據(jù)庫廠商的JDBCDriveAPI6.2JDBC概述java.sql.Statement:6.2

JDBC概述6.2.1創(chuàng)建數(shù)據(jù)庫連接6.2.2SQL的執(zhí)行6.2.3SQL執(zhí)行結果的處理6.2JDBC概述6.2.1創(chuàng)建數(shù)據(jù)庫連接6.2.1

創(chuàng)建數(shù)據(jù)庫連接在Java程序中要操作數(shù)據(jù)庫,一般應該通過如下幾步。1.下載數(shù)據(jù)庫開發(fā)所需要的驅動包用戶可以從對應的數(shù)據(jù)庫廠商的官網(wǎng)進行下載,例如,下載MySQL驅動包,如圖6.3所示,選擇“JDBCDriverforMySQL”進行下載。下載的驅動包是一個壓縮包,將包內的“mysql-connector-java-5.1.42-bin.jar”復制到“WebRoot\lib”文件夾下,如圖6.4所示。6.2.1創(chuàng)建數(shù)據(jù)庫連接在Java程序中要操作數(shù)據(jù)庫,一6.2.1

創(chuàng)建數(shù)據(jù)庫連接圖6.3下載MySQL驅動包圖6.4加載MySQL驅動包6.2.1創(chuàng)建數(shù)據(jù)庫連接圖6.3下載MySQL驅動包圖6.2.1

創(chuàng)建數(shù)據(jù)庫連接2.數(shù)據(jù)庫管理工具在開發(fā)中,我們一般會創(chuàng)建一個專用于創(chuàng)建數(shù)據(jù)庫連接和釋放數(shù)據(jù)庫連接的工具類。建立與數(shù)據(jù)庫的連接需要完成如下兩個步驟。(1)加載驅動類到內存Class.forName("com.mysql.jdbc.Driver");(2)創(chuàng)建與數(shù)據(jù)源的連接Connectioncon=DriverManager.getConnection(Stringurl,Stringusername,Stringpassword);6.2.1創(chuàng)建數(shù)據(jù)庫連接2.數(shù)據(jù)庫管理工具6.2.2

SQL的執(zhí)行在實際開發(fā)中,當需要訪問數(shù)據(jù)庫時,只需要調用以下方法:

Connectionconn=DBUtil.getConnection();就可以獲得一個java.sql.Connection類型的數(shù)據(jù)庫連接對象,通過這個連接對象,用戶可以操作數(shù)據(jù)庫,發(fā)送目標SQL給數(shù)據(jù)庫,并接收響應結果。6.2.2SQL的執(zhí)行在實際開發(fā)中,當需要訪問數(shù)據(jù)庫時,6.2.2

SQL的執(zhí)行在已建立數(shù)據(jù)庫連接的基礎上,向數(shù)據(jù)庫發(fā)送要執(zhí)行的SQL語句的接口是Statement。Statement用于執(zhí)行靜態(tài)的SQL語句。(1)java.sql.Statementjava.sql.Statement類型的對象,是通過java.sql.Connection對象獲得的,其代碼如下:Statementst=conn.createStatement();所獲得的Statement對象st,可以用來執(zhí)行SQL語句,Statement執(zhí)行SQL語句的主要方法有兩個:intexecuteUpdate(Stringsql);ResultSetexecuteQuery(Stringsql);6.2.2SQL的執(zhí)行在已建立數(shù)據(jù)庫連接的基礎上,向數(shù)據(jù)6.2.2

SQL的執(zhí)行其中,executeUpdate(Stringsql)方法可用來執(zhí)行數(shù)據(jù)庫的更新操作。該方法的返回值類型為int,代表影響的記錄條數(shù),即插入了幾條數(shù)據(jù),修改了幾條數(shù)據(jù),刪除了幾條數(shù)據(jù)等。而executeQuery(Stringsql)方法可用來執(zhí)行數(shù)據(jù)庫的查詢操作。該方法的返回值類型是java.sql.ResultSet,該類型能夠存儲數(shù)據(jù)庫返回的所有記錄,并支持按條讀取結果數(shù)據(jù)。6.2.2SQL的執(zhí)行其中,executeUpdate(6.2.2

SQL的執(zhí)行(2)java.sql.PreparedStatement接口在Statement中可以看到,動態(tài)SQL的生成是通過字符串拼接而成的,但是字符串拼接會帶來很多的安全隱患,其中最為常見的安全漏洞就是SQL注入。下面以登錄功能為例,在.zzti.dao包下的UserDAO接口中定義登錄判斷方法,代碼如下:publicUserDOfindUser(Stringusername,Stringpassword)throwsSQLException;具體代碼如下:6.2.2SQL的執(zhí)行(2)java.sql.Prepa6.2.2SQL的執(zhí)行在代碼的第6行,我們將拼接后的SQL語句打印到控制臺進行觀察。在第12行處,需要將獲得的數(shù)據(jù)庫查詢結果進行封裝,這里暫不實現(xiàn)這個功能。下面先來創(chuàng)建一個.zzti.dao.impl.mysql.

jdbc.test.UserDAOImplTest類,對方法findUser進行測試,具體代碼如下。1publicUserDOfindUser(Stringusername,Stringpassword)throwsSQLException{2 Stringsql="select*fromuserwhereusername='"+3 username+4 "'andpassword='"+5 password+"'";6 System.out.println("登錄sql是:"+sql);7 Connectionconn=DBUtil.getConnection();8 Statementst=conn.createStatement();9 ResultSetrs=st.executeQuery(sql);10 if(rs.next()){11 UserDOuser=newUserDO();12 //將查詢結果封裝到user對象中,此處先不處理13 returnuser;14 }15 returnnull;16 }6.2.2SQL的執(zhí)行1publicUserDO6.2.2SQL的執(zhí)行Assert.assertNotNull(Objecto)是Junit的斷言,該斷言方法判斷對象o是否為空,為空則當前測試方法通過,否則測試方法失敗。執(zhí)行結果顯示,使用不存在的用戶名和密碼,調用登錄方法執(zhí)行結果為登錄正常。在輸出的SQL結果顯示,最終執(zhí)行的SQL如下:

1publicclassUserDAOImplTest{2 privateUserDAOuserDAO=(UserDAO)3 DAOFactory.getDAO(".zzti.dao.impl.mysql.jdbc.UserDAOImpl");4 @Test5 publicvoidtestFinUser(){6 Stringusername="test'or1=1#";7 Stringpassword="";8 try{9 Assert.assertNull(userDAO.findUser(username,password));10 }catch(SQLExceptione){11 e.printStackTrace();12 fail("出現(xiàn)異常,執(zhí)行失敗");13 }14 }15}6.2.2SQL的執(zhí)行1publicclass6.2.2SQL的執(zhí)行select*fromuserwhereusername='test'or1=1#'andpassword=‘’在這個SQL中,“#”代表MySQL中的注釋。該語句的本意是從數(shù)據(jù)庫中獲取全部的數(shù)據(jù),因為“or1=1”使得這個條件恒為真。select*fromuserwhereusername='test'or1=16.2.2SQL的執(zhí)行select*fromuser6.2.2SQL的執(zhí)行為了避免SQL注入的問題,JDBC提供了一種SQL預編譯的機制,即PreparedStatement。首先用戶提交的SQL中可以不指定具體的參數(shù),對于可變值部分讓用戶使用“?”(即占位符)來代替。然后再對SQL中的占位符單獨設置值,將兩者提交給數(shù)據(jù)庫引擎進行編譯,此時數(shù)據(jù)庫引擎僅僅編譯帶有占位符“?”的SQL語句,等到編譯完成后,在執(zhí)行SQL時,將參數(shù)帶入編譯結果,此時,參數(shù)就只會作為參數(shù)整體進行數(shù)據(jù)比較,而不會作為SQL語法的一部分。6.2.2SQL的執(zhí)行為了避免SQL注入的問題,JDBC提6.2.2SQL的執(zhí)行PreparedStatement對象的創(chuàng)建方式如下:PreparedStatementps=conn.prepareStatement(Stringsql);而SQL也需要進行相應的改寫:Stringsql="select*fromuserwhereusername=?andpassword=?";與之前的SQL對比可以發(fā)現(xiàn),原來的形式參數(shù)部分被占位符“?”代替,那么就需要將形式參數(shù)與具體的“?”綁定。綁定操作可通過調用setXXX方法來完成,其中,XXX是與該參數(shù)相對應的類型。例如,如果參數(shù)的數(shù)據(jù)類型是long,則使用的方法就是setLong。setXXX方法的第一個參數(shù)是要設置的參數(shù)的序數(shù)位置,第二個參數(shù)是設置給該參數(shù)的值。例如,上述SQL將第一個參數(shù)設為形式參數(shù)username,第二個參數(shù)設為形式參數(shù)password,代碼如下所示:ps.setString(1,username);ps.setString(2,password);6.2.2SQL的執(zhí)行PreparedStatement對6.2.3SQL執(zhí)行結果處理無論是Statement,還是PreparedStatement,在執(zhí)行SQL的時候,主要應用的執(zhí)行方法是executeQuery和executeUpdate,Statement在執(zhí)行execute*方法時,需要以SQL為字符串參數(shù)進行傳遞,而PreparedStatement則不需要參數(shù)。調用規(guī)則總結如表6.2所示。6.2.3SQL執(zhí)行結果處理無論是Statement,還是6.2.3SQL執(zhí)行結果處理類名方法定義說明StatementResultSetexecuteQuery(Stringsql)執(zhí)行select等StatementintexecuteUpdate(Stringsql)執(zhí)行insert、update、delete等PreparedStatementResultSetexecuteQuery()執(zhí)行select等PreparedStatementintexecuteUpdate(Stringsql)執(zhí)行insert、update、delete等表6.2SQL執(zhí)行結果6.2.3SQL執(zhí)行結果處理類名方法定義說明6.3數(shù)據(jù)庫連接池創(chuàng)建數(shù)據(jù)庫連接是一個十分耗時的操作,也容易讓數(shù)據(jù)庫產生安全隱患。因此,在程序初始化的時候,集中創(chuàng)建了多個數(shù)據(jù)庫連接,并對它們進行集中管理,以供程序使用,這樣就可以保證較快的數(shù)據(jù)庫讀/寫速度,而且更加安全可靠。數(shù)據(jù)庫連接池的運行原理如圖6.16所示。6.3數(shù)據(jù)庫連接池創(chuàng)建數(shù)據(jù)庫連接是一個十分耗時的操作,也容6.3數(shù)據(jù)庫連接池Servlet1Servlet2......ServletnDAO1.....DAOmMySQLuser1......usersConnectionConnection......Connection圖6.16數(shù)據(jù)庫連接池原理6.3數(shù)據(jù)庫連接池Servlet1Servlet2....6.3數(shù)據(jù)庫連接池6.3.1DataSource6.3.2Tomcat數(shù)據(jù)源6.3.3DBCP6.3數(shù)據(jù)庫連接池6.3.1DataSource6.3.1DataSourceJDBC1.0原來是用DriverManager類來產生一個對數(shù)據(jù)源的連接。JDBC2.0用一種替代的方法,使用java.sql.DataSource實現(xiàn),代碼變得更小巧精致,也更容易控制。編寫數(shù)據(jù)庫連接池需實現(xiàn)Java.sql.DataSource接口。DataSource接口中定義了兩個重載的getConnection方法:6.3.1DataSourceJDBC1.0原來是用Dri6.3.1DataSourceConnectiongetConnection()ConnectiongetConnection(Stringusername,Stringpassword)開發(fā)數(shù)據(jù)庫連接池實現(xiàn)DataSource接口時,在DataSource的實現(xiàn)類的構造方法中批量創(chuàng)建與數(shù)據(jù)庫的連接,并把創(chuàng)建的連接加入存儲java.sql.Connection對象的集合中。實現(xiàn)getConnection方法,讓getConnection方法每次調用時,從存儲java.sql.Connection對象的集合中取一個Connection返回給用戶。6.3.1DataSourceConnectionget6.3.2Tomcat數(shù)據(jù)源Tomcat提供了數(shù)據(jù)源和連接池的實現(xiàn),開發(fā)者直接使用即可。這里的Tomcat需要JDBC驅動,而不再是應用程序需要JDBC驅動,所以要先將對應數(shù)據(jù)庫的JDBC驅動類庫復制到Tomcat目錄中的lib文件夾下,供Tomcat調用。首先在Tomcat目錄中的“l(fā)ib”目錄下放入數(shù)據(jù)庫驅動jar包,在工程的“META-INF”目錄下創(chuàng)建一個“context.xml”文件,如圖6.17和圖6.18所示。6.3.2Tomcat數(shù)據(jù)源Tomcat提供了數(shù)據(jù)源和連接6.3.2Tomcat數(shù)據(jù)源圖6.17添加MySQL驅動包圖6.18工程添加配置文件6.3.2Tomcat數(shù)據(jù)源圖6.17添加MySQL驅動6.3.2Tomcat數(shù)據(jù)源“context.xml”的配置內容如下:這些屬性含義如表6.4所示。1<Context>2<Resourcename="shop"3 auth="Container"4 type="javax.sql.DataSource"5 username="root"6 password="root"7 driverClassName="com.mysql.jdbc.Driver"8 url="jdbc:mysql://localhost:3306/shop"9 initialSize="10"10 maxActive="20"11 maxIdle="4"/>12</Context>6.3.2Tomcat數(shù)據(jù)源“context.xml”的配6.3.2Tomcat數(shù)據(jù)源鍵名含義name指定資源相對于java:comp/env上下文的JNDI名auth指定資源的管理者(默認Container即可)type指定資源所屬的Java類的完整限定名(默認即可)maxIdle指定連接池中保留的空閑數(shù)據(jù)庫連接的最大數(shù)目maxWait指定等待一個數(shù)據(jù)庫連接成為可用狀態(tài)的最大時間,單位毫秒username指定連接數(shù)據(jù)庫的用戶名password指定連接數(shù)據(jù)庫的密碼driverClassName指定JDBC驅動程序類名url指定連接數(shù)據(jù)庫的URL表6.4Tomcat數(shù)據(jù)源配置文件屬性解析6.3.2Tomcat數(shù)據(jù)源鍵名含義name指定資6.3.2Tomcat數(shù)據(jù)源這里<Resource>元素的name屬性即為我們使用JNDI去檢索的關鍵字,在本例中為“shop”。接下來采用與之前工程相同的方式,創(chuàng)建數(shù)據(jù)庫工具類.zzti.util.tomcat.DBUtil來簡化對數(shù)據(jù)庫的操作。6.3.2Tomcat數(shù)據(jù)源這里<Resource>元素的6.3.2Tomcat數(shù)據(jù)源1publicclassDBUtil{2privatestaticDataSourceds=null;3static{4try{5ContextinitCtx=newInitialContext();6ContextenvCtx=(Context)initCtx.lookup("java:comp/env");7ds=(DataSource)envCtx.lookup("shop");8//根據(jù)<Resource>元素的name屬性值到JNDI容器中檢索連接池對象9}catch(Exceptione){10thrownewExceptionInInitializerError(e);11}12}13publicstaticConnectiongetConnection()throwsSQLException{14returnds.getConnection();//利用數(shù)據(jù)源獲取連接15}16}6.3.2Tomcat數(shù)據(jù)源1publicclas6.3.3DBCP數(shù)據(jù)庫連接池(DataBaseConnectionPool,DBCP)是Java數(shù)據(jù)庫連接池的一種,由Apache開發(fā),通過數(shù)據(jù)庫連接池可以讓程序自動管理數(shù)據(jù)庫連接的釋放和斷開。DBCP是Apache上的一個Java連接池項目,也是Tomcat使用的連接池組件。單獨使用DBCP需要準備3個包:commons-dbcp-版本.jar;commons-pool-版本.jar;commons-logging-版本.jar。6.3.3DBCP數(shù)據(jù)庫連接池(DataBaseConn6.3.3DBCPDBCP的配置文件的內容如下,其參數(shù)含義如表6.5所示。參數(shù)描述username傳遞給JDBC驅動的用于建立連接的用戶名password傳遞給JDBC驅動的用于建立連接的密碼url傳遞給JDBC驅動的用于建立連接的URLdriverClassName使用的JDBC驅動的完整有效的Java類名connectionProperties當建立新連接時被發(fā)送給JDBC驅動的連接參數(shù)表6.5DBCP常見配置參數(shù)含義6.3.3DBCPDBCP的配置文件的內容如下,其參數(shù)含義6.4DBUtils框架簡介CommonsDBUtils是Apache組織提供的一個對JDBC進行簡單封裝的開源工具類庫,使用它能夠簡化JDBC應用程序的開發(fā),同時也不會影響程序的性能。DBUtils是Java編程中的數(shù)據(jù)庫操作實用工具,簡單且實用。6.4DBUtils框架簡介CommonsDBUtil6.4DBUtils框架簡介DBUtils對于數(shù)據(jù)表的讀操作,它可以把結果轉換成List、Array、Set等Java集合,以便于程序員操作。對于數(shù)據(jù)表的寫操作,也變得很簡單,只需寫SQL語句;可以使用數(shù)據(jù)源、JNDI、數(shù)據(jù)庫連接池等技術來優(yōu)化性能,重用已經構建好的數(shù)據(jù)庫連接對象,而不必像PHP、ASP那樣,需要費時費力地不斷重復構建和析構這樣的對象。CommonsDBUtils的核心類有3個:mons.dbutils.ResultSetHandler、mons.dbutils.QueryRunner、mons.dbutils.DBUtils。6.4DBUtils框架簡介DBUtils對于數(shù)據(jù)表的讀6.4DBUtils框架簡介6.4.1QueryRunner6.4.2ResultSetHandler6.4.3資源釋放6.4DBUtils框架簡介6.4.1QueryRun6.4.1QueryRunnerQueryRunner類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的數(shù)據(jù)庫操作,能夠大大減少編碼量。(1)QueryRunner類的構造方法①默認的構造方法QueryRunnerqueryRunner=newQueryRunner();。②需要一個javax.sql.DataSource來作參數(shù)的構造方法。QueryRunnerqr=newQueryRunner(DBUtil.getDataSource())6.4.1QueryRunnerQueryRunner類6.4.1QueryRunner(2)QueryRunner類的主要方法①publicObjectquery(Connectionconn,Stringsql,Object[]params,ResultSetHandlerrsh)throwsSQLException:執(zhí)行一個查詢操作,在這個查詢中,對象數(shù)組中的每個元素值被用來作為查詢語句的置換參數(shù)。該方法會自行處理PreparedStatement和ResultSet的創(chuàng)建和關閉流程。②publicObjectquery(Stringsql,Object[]params,ResultSetHandlerrsh)throwsSQLException:基本與第一種方法相同,唯一的不同在于它不將數(shù)據(jù)庫連接提供給方法,并且它是從提供給構造方法的DataSource數(shù)據(jù)源或使用setDataSource方法設置的數(shù)據(jù)源。6.4.1QueryRunner(2)QueryRunn6.4.1QueryRunner③publicObjectquery(Connectionconn,Stringsql,ResultSetHandlerrsh)throwsSQLException:執(zhí)行一個不需要置換參數(shù)的查詢操作。④publicintupdate(Connectionconn,Stringsql,Object[]params)throwsSQLException:用來執(zhí)行一個更新操作,如插入、更新或刪除。⑤publicintupdate(Connectionconn,Stringsql)throwsSQLException:用來執(zhí)行一個不需要置換參數(shù)的更新操作。6.4.1QueryRunner③publicObj6.4.2ResultSetHandlerResultSetHandler接口用于處理java.sql.ResultSet,將數(shù)據(jù)按要求轉換為另一種形式。ResultSetHandler接口提供了一個單獨的處理java.sql.ResultSet的方法:

Objecthandle(java.sql.ResultSetrs)6.4.2ResultSetHandlerResultSe6.4.2ResultSetHandler(1)查詢類操作方法介紹ResultSetHandler接口的實現(xiàn)類見表6.6,下面對每個接口的實現(xiàn)類的具體使用方式進行介紹。功能實現(xiàn)類單行數(shù)據(jù)處理ScalarHandler、ArrayHandler、MapHandler、BeanHandler多行數(shù)據(jù)處理BeanListHandler、ArrayListHandler、MapListHandler、

ColumnListHandler、KeyedHandler、BeanMapHandler可供擴展的類BaseResultSetHandler表6.6ResultSetHandler接口實現(xiàn)類說明6.4.2ResultSetHandler(1)查詢類操作6.4.2ResultSetHandler①ArrayHandler:把結果集中的第一行數(shù)據(jù)轉換成對象數(shù)組,示例代碼如下。②ArrayListHandler:把結果集中的每一行數(shù)據(jù)都轉換成一個對象數(shù)組,再存放到List中,示例代碼如下。1publicstaticvoidqueryToArray(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromauction";4 Object[]rs=queryRunner.query(conn,sql,newArrayHandler());5 for(inti=0;i<rs.length;i++){6 System.out.print("第一列:"+rs[i]+"\t");7 }8 System.out.print("\n");9 }1publicstaticvoidqueryToArrayList(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromauction";4 Listrs=queryRunner.query(conn,sql,newArrayListHandler());5 for(Objectrecord:rs){6 System.out.println(Arrays.toString((Object[])record));7 }8 }6.4.2ResultSetHandler①ArrayH6.4.2ResultSetHandler③BeanHandler<T>:把結果集中的第一行數(shù)據(jù)封裝到一個對應的JavaBean實例中,示例代碼如下。④BeanListHandler<T>:把結果集中的每一行數(shù)據(jù)都封裝到一個對應的JavaBean實例中,再存放到List中,示例代碼如下。1publicstaticvoidqueryToBean(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 4 AuctionDOauc=queryRunner.query(conn,5"select*fromauction",6newBeanHandler<AuctionDO>(AuctionDO.class));7 System.out.println(auc);8 }1publicstaticvoidqueryToBeanList(Connectionconn)throwsSQLException{2 Stringsql="select*fromauction";3 QueryRunnerqueryRunner=newQueryRunner();4 List<AuctionDO>list=queryRunner.query(conn,sql,5 newBeanListHandler<AuctionDO>(AuctionDO.class));6 for(inti=0;i<list.size();i++){7 System.out.println(list.get(i));8 }9 }6.4.2ResultSetHandler③BeanHa6.4.2ResultSetHandler⑤MapHandler:把結果集中的第一行數(shù)據(jù)封裝到一個Map中,key是列名,value就是對應的值,示例代碼如下。⑥MapListHandler:把結果集中的每一行數(shù)據(jù)都封裝到一個Map中,然后再存放到List,示例代碼如下。1publicstaticvoidqueryToMap(Connectionconn)throwsSQLException{2 Stringsql="select*fromauction";3 QueryRunnerqueryRunner=newQueryRunner();4 Map<String,Object>map=queryRunner.query(conn,sql,newMapHandler());5 Set<Entry<String,Object>>set=map.entrySet();6 for(Entry<String,Object>entry:set){7 System.out.println(entry.getKey()+":"+entry.getValue());8 }9}1publicstaticvoidqueryToMapList(Connectionconn)throwsSQLException{2 Stringsql="select*fromauction";3 QueryRunnerqueryRunner=newQueryRunner();4 ist<Map<String,Object>>list=queryRunner.query(conn,sql,newMapListHandler());5 for(Map<String,Object>mapValue:list){6 Set<Entry<String,Object>>set1=mapValue.entrySet();7 for(Entry<String,Object>entry:set1){8 System.out.println(entry.getKey()+":"+entry.getValue());9 }10}11 }6.4.2ResultSetHandler⑤MapHan6.4.2ResultSetHandler⑦ColumnListHandler<T>:把結果集中的某一列的數(shù)據(jù)存放到List中,示例代碼如下。⑧KeyedHandler<K>:把結果集中的每一行數(shù)據(jù)都封裝到一個Map中(List),再把這些Map存到一個Map里,其key為指定的列,示例代碼如下。1publicstaticvoidqueryToColList(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromauction";//whereid=14 List<Object>list=(List<Object>)queryRunner.query(conn,sql,5 newColumnListHandler("name"));6 System.out.println(list);7}1publicstaticvoidqueryToKeyedHandler(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromusers";4 Map<Integer,Map<String,Object>>rs1=queryRunner.query(conn,sql,5 newKeyedHandler<Integer>(1));6 System.out.println("KeyedHandler:"+rs1);7 Map<Integer,Map<String,Object>>rs2=queryRunner.query(conn,sql,8 newKeyedHandler<Integer>("title"));9 System.out.println("KeyedHandler:"+rs2);10}6.4.2ResultSetHandler⑦Column6.4.2ResultSetHandler⑨BeanMapHandler<K,V>:用于獲取所有結果集,將每行結果集轉換為Javabean作為value,并指定某列為key,封裝到HashMap中。相當于對每行數(shù)據(jù)進行與BeanHandler相同的處理后,再指定列值為Key封裝到HashMap中。1publicstaticvoidqueryToBeanMap(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromauction";4 Map<Integer,AuctionDO>rs=queryRunner.query(conn,sql,5 newBeanMapHandler<Integer,AuctionDO>(AuctionDO.class,1));6 System.out.println("BeanMapHandler:"+rs);7}6.4.2ResultSetHandler⑨BeanMa6.4.2ResultSetHandler⑩ScalarHandler<T>:獲取結果集中第一行數(shù)據(jù)指定列的值,常用來進行單值查詢,示例代碼如下。(2)更新類操作方法介紹在執(zhí)行insert、delete、update等更新數(shù)據(jù)庫方法時,將調用QueryRunner的update方法,該方法返回影響的記錄條數(shù)。1publicstaticvoidqueryToBeanMap(Connectionconn)throwsSQLException{2 QueryRunnerqueryRunner=newQueryRunner();3 Stringsql="select*fromauction";4 intrs=runner.query(conn,sql,newScalarHandler<Integer>());5 System.out.println("ScalarHandler:"+rs);6 Stringrs=runner.query(conn,sql,newScalarHandler<String>(2));7 //或者Stringrs=runner.query(conn,sql,newScalarHandler<String>("userName"));8 System.out.println("ScalarHandler:"+rs);9}6.4.2ResultSetHandler⑩Scalar6.4.3資源釋放DBUtils框架提供了關閉連接、裝載JDBC驅動程序等常規(guī)工作的工具類,里面的所有方法都是靜態(tài)的。主要方法如下:publicstaticvoidclose()throwsSQLExceptionDBUtils類提供了3個重載的關閉方法。這些方法檢查所提供的參數(shù)是否為NULL,如果不是,它們就關閉Connection、Statement和ResultSet6.4.3資源釋放DBUtils框架提供了關閉連接、裝載6.5簡易購物商城使用DBCP作為數(shù)據(jù)庫連接池連接數(shù)據(jù)庫,與DBUtils框架整合來改寫簡易購物商城的前臺系統(tǒng),將商品、用戶、個人信息持久化存儲到MySQL數(shù)據(jù)庫中。6.5簡易購物商城使用DBCP作為數(shù)據(jù)庫連接池連接數(shù)據(jù)庫,6.5簡易購物商城6.5.1數(shù)據(jù)庫設計6.5.2DAO接口實現(xiàn)6.5簡易購物商城6.5.1數(shù)據(jù)庫設計6.5.1數(shù)據(jù)庫設計根據(jù)前面章節(jié)的需求分析,簡易購物商城前臺系統(tǒng)共設計數(shù)據(jù)庫表三張,首先創(chuàng)建數(shù)據(jù)庫shop,然后在數(shù)據(jù)庫shop中設計auction、user和personalInfo三張數(shù)據(jù)表,具體表結構如圖6.23~圖6.25所示。圖6.23action商品表圖6.24user用戶表圖6.25personal個人信息表6.5.1數(shù)據(jù)庫設計根據(jù)前面章節(jié)的需求分析,簡易購物商城前6.5.2DAO接口實現(xiàn)首先在工程中導入相關的jar包,并創(chuàng)建.zzti.dao包中各個接口的具體實現(xiàn)類,放在.zzti.dao.impl.mysql包下,如圖6.26和圖6.27所示。圖6.26導入相關jar包圖6.27基于DBUtils的DAO實現(xiàn)6.5.2DAO接口實現(xiàn)首先在工程中導入相關的jar包,并6.5.2DAO接口實現(xiàn)各個實現(xiàn)類的具體實現(xiàn)代碼如下所示。(1)AuctionDAOImpl1publicclassAuctionDAOImplimplementsAuctionDAO{2 @Override3 publicAuctionDOgetAuction(Stringid)throwsSQLException{4 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());5 Stringsql="select*fromauctionwhereid=?";6 AuctionDOauctionDO=queryrunner.query(sql,7 newBeanHandler<AuctionDO>(AuctionDO.class),id);8 returnauctionDO;9 }10 @Override11 publicvoidaddAuction(AuctionDOauc)throwsSQLException{12 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());13 Stringsql="insertintoauctionvalues(?,?,?,?)";14 Object[]params=newObject[]{UUID.randomUUID().toString(),15 auc.getTitle(),auc.getDescription(),auc.getPrice()};16 queryrunner.update(sql,params);17 }6.5.2DAO接口實現(xiàn)各個實現(xiàn)類的具體實現(xiàn)代碼如下所示。6.5.2DAO接口實現(xiàn)各個實現(xiàn)類的具體實現(xiàn)代碼如下所示。(1)AuctionDAOImpl18 @Override19 publicList<AuctionDO>getAll()throwsSQLException{20 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());21 Stringsql="select*fromauction";22 List<AuctionDO>list=queryrunner.query(sql,23 newBeanListHandler<AuctionDO>(AuctionDO.class));24 returnlist;25 }26 @Override27 publicvoiddeleteAuction(Stringid)throwsSQLException{28 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());29 Stringsql="deletefromauctionwhereid=?";30 queryrunner.update(sql,id);31 }32 @Override33 publicvoidupdateAuction(AuctionDOauc)throwsSQLException{34 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());35 Stringsql="updateauctionsettitle=?,description=?,price=?whereid=?";36 Object[]params=newObject[]{auc.getTitle(),37 auc.getDescription(),auc.getPrice(),auc.getId()};38 queryrunner.update(sql,params);39 }40}

6.5.2DAO接口實現(xiàn)各個實現(xiàn)類的具體實現(xiàn)代碼如下所示。6.5.2DAO接口實現(xiàn)(2)PersonalDAOImpl1publicclassPersonalDAOImplimplementsPersonalDAO{2 @Override3 publicPersonalInfoDOgetPersonalInfo(Stringusername)throwsSQLException{4 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());5 Stringsql="select*frompersonalInfowhereusername=?";6 PersonalInfoDOp=queryrunner.query(sql,7 newBeanHandler<PersonalInfoDO>(PersonalInfoDO.class),username);8 returnp;9 }10@Override11publicvoidsetPersonalInfo(Stringusername,PersonalInfoDOp)throwsSQLException12{13 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());14 Stringsql="insertintopersonalInfovalues(?,?,?,?,?,?,?,?,?,?)";15 Object[]params=newObject[]{16 username,17 p.getAge(),18 p.getGender(),19 p.getAddress(),20 p.getTel(),21 p.getEmail(),22 p.getGraduateSchool(),23 p.getHighestEducation(),24 p.getMajor(),25 p.getRealName()26 };27 queryrunner.update(sql,params);28 }29}

6.5.2DAO接口實現(xiàn)(2)PersonalDAOImp6.5.2DAO接口實現(xiàn)(3)UserDAOImpl1publicclassUserDAOImplimplementsUserDAO{2publicList<UserDO>getAll()throwsSQLException{3 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());4 Stringsql="select*fromuser";5 List<UserDO>list=queryrunner.query(sql,6 newBeanListHandler<UserDO>(UserDO.class));7 returnlist;8 }9 publicUserDOfindUser(Stringusername,Stringpassword)throwsSQLException{10 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());11 Stringsql="select*fromuserwhereusername=?andpassword=?";12 Object[]params=newObject[]{username,password};13 UserDOuserDO=queryrunner.query(sql,14 newBeanHandler<UserDO>(UserDO.class),params);15 returnuserDO;16 }17 publicintinsertUser(UserDOu)throwsSQLException{18 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());19 Stringsql="insertintouservalues(?,?)";20 Object[]params=newObject[]{u.getUsername(),u.getPassword()};21 returnqueryrunner.update(sql,params);22 }23 publicintdeleteUser(Stringid)throwsSQLException{24 QueryRunnerqueryrunner=newQueryRunner(DBUtil.getDataSource());25 Stringsql="deletefromuserwhereusername=?";26 returnqueryrunner.update(sql,id);27 }28}

6.5.2DAO接口實現(xiàn)(3)UserDAOImpl1第6章數(shù)據(jù)庫整合開發(fā)

第6章數(shù)據(jù)庫整合開發(fā)本章內容MySQL簡介

JDBC概述數(shù)據(jù)庫連接池

DBUtils框架簡介簡易購物商城本章內容MySQL簡介6.1MySQL簡介MySQL是一個關系型數(shù)據(jù)庫,它由瑞典MySQLAB公司開發(fā),目前屬于Oracle旗下的產品。MySQL是最流行的關系型數(shù)據(jù)庫管理系統(tǒng)之一,在Web應用方面,MySQL是最好的關系數(shù)據(jù)庫管理系統(tǒng)(RelationalDataBaseManagementSystem,RDBMS)應用軟件。6.1MySQL簡介MySQL是一個關系型數(shù)據(jù)庫,它由瑞6.2

JDBC概述Java數(shù)據(jù)庫連接技術(JavaDataBaseConnectivity,JDBC)是Java訪問數(shù)據(jù)庫資源的標準,JDBC標準定義了一組JavaAPI,允許用戶寫出SQL語句,然后交給數(shù)據(jù)庫。6.2JDBC概述Java數(shù)據(jù)庫連接技術(JavaD6.2

JDBC概述如圖6.1所示,如果沒有JDBC或者ODBC,開發(fā)人員必須使用不同的一組API來訪問不同的數(shù)據(jù)庫;而有了JDBC或者ODBC,則只需要使用一組API,再加上數(shù)據(jù)庫廠商提供的數(shù)據(jù)庫驅動程序就可以訪問不同的數(shù)據(jù)庫了,如圖6.2所示。所以,利用JDBC,我們就可以把同一個企業(yè)級Java應用移植到另一個數(shù)據(jù)庫應用上。6.2JDBC概述如圖6.1所示,如果沒有JDBC或6.2

JDBC概述圖6.1應用程序直接訪問數(shù)據(jù)庫圖6.2應用程序訪問JDBC6.2JDBC概述圖6.1應用程序直接訪問數(shù)據(jù)庫圖6.6.2

JDBC概述JDBC主要包含兩部分:面向Java程序員的JDBCAPI和面向數(shù)據(jù)庫廠商的JDBCDriveAPI。1.面向Java程序員的JDBCAPI它主要由一系列的接口定義所構成。java.sql.DriveManager:該接口定義了用來處理裝載驅動的程序,并且為創(chuàng)建新的數(shù)據(jù)庫連接提供支持。java.sql.Connection:該接口定義了實現(xiàn)對某一種指定數(shù)據(jù)庫連接的功能。6.2JDBC概述JDBC主要包含兩部分:面向Java程6.2

JDBC概述java.sql.Statement:該接口定義了在一個給定的連接中作為SQL語句執(zhí)行聲明的容器以實現(xiàn)對數(shù)據(jù)庫的操作。它主要包含有如下兩種子類型。java.sql.PreparedStatement:該接口定義了用于執(zhí)行帶或不帶IN參數(shù)的預編譯SQL語句。java.sql.CallableStatement:該接口定義了用于執(zhí)行數(shù)據(jù)庫的存儲過程的調用。java.sql.ResultSet:該接口定義了執(zhí)行數(shù)據(jù)庫的操作后返回的結果集。2.面向數(shù)據(jù)庫廠商的JDBCDriveAPI6.2JDBC概述java.sql.Statement:6.2

JDBC概述6.2.1創(chuàng)建數(shù)據(jù)庫連接6.2.2SQL的執(zhí)行6.2.3SQL執(zhí)行結果的處理6.2JDBC概述6.2.1創(chuàng)建數(shù)據(jù)庫連接6.2.1

創(chuàng)建數(shù)據(jù)庫連接在Java程序中要操作數(shù)據(jù)庫,一般應該通過如下幾步。1.下載數(shù)據(jù)庫開發(fā)所需要的驅動包用戶可以從對應的數(shù)據(jù)庫廠商的官網(wǎng)進行下載,例如,下載MySQL驅動包,如圖6.3所示,選擇“JDBCDriverforMySQL”進行下載。下載的驅動包是一個壓縮包,將包內的“mysql-connector-java-5.1.42-bin.jar”復制到“WebRoot\lib”文件夾下,如圖6.4所示。6.2.1創(chuàng)建數(shù)據(jù)庫連接在Java程序中要操作數(shù)據(jù)庫,一6.2.1

創(chuàng)建數(shù)據(jù)庫連接圖6.3下載MySQL驅動包圖6.4加載MySQL驅動包6.2.1創(chuàng)建數(shù)據(jù)庫連接圖6.3下載MySQL驅動包圖6.2.1

創(chuàng)建數(shù)據(jù)庫連接2.數(shù)據(jù)庫管理工具在開發(fā)中,我們一般會創(chuàng)建一個專用于創(chuàng)建數(shù)據(jù)庫連接和釋放數(shù)據(jù)庫連接的工具類。建立與數(shù)據(jù)庫的連接需要完成如下兩個步驟。(1)加載驅動類到內存Class.forName("com.mysql.jdbc.Driver");(2)創(chuàng)建與數(shù)據(jù)源的連接Connectioncon=DriverManager.getConnection(Stringurl,Stringusername,Stringpassword);6.2.1創(chuàng)建數(shù)據(jù)庫連接2.數(shù)據(jù)庫管理工具6.2.2

SQL的執(zhí)行在實際開發(fā)中,當需要訪問數(shù)據(jù)庫時,只需要調用以下方法:

Connectionconn=DBUtil.getConnection();就可以獲得一個java.sql.Connection類型的數(shù)據(jù)庫連接對象,通過這個連接對象,用戶可以操作數(shù)據(jù)庫,發(fā)送目標SQL給數(shù)據(jù)庫,并接收響應結果。6.2.2SQL的執(zhí)行在實際開發(fā)中,當需要訪問數(shù)據(jù)庫時,6.2.2

SQL的執(zhí)行在已建立數(shù)據(jù)庫連接的基礎上,向數(shù)據(jù)庫發(fā)送要執(zhí)行的SQL語句的接口是Statement。Statement用于執(zhí)行靜態(tài)的SQL語句。(1)java.sql.Statementjava.sql.Statement類型的對象,是通過java.sql.Connection對象獲得的,其代碼如下:Statementst=conn.createStatement();所獲得的Statement對象st,可以用來執(zhí)行SQL語句,Statement執(zhí)行SQL語句的主要方法有兩個:intexecuteUpdate(Stringsql);ResultSetexecuteQuery(Stringsql);6.2.2SQL的執(zhí)行在已建立數(shù)據(jù)庫連接的基礎上,向數(shù)據(jù)6.2.2

SQL的執(zhí)行其中,executeUpdate(Stringsql)方法可用來執(zhí)行數(shù)據(jù)庫的更新操作。該方法的返回值類型為int,代表影響的記錄條數(shù),即插入了幾條數(shù)據(jù),修改了幾條數(shù)據(jù),刪除了幾條數(shù)據(jù)等。而executeQuery(Stringsql)方法可用來執(zhí)行數(shù)據(jù)庫的查詢操作。該方法的返回值類型是java.sql.ResultSet,該類型能夠存儲數(shù)據(jù)庫返回的所有記錄,并支持按條讀取結果數(shù)據(jù)。6.2.2SQL的執(zhí)行其中,executeUpdate(6.2.2

SQL的執(zhí)行(2)java.sql.PreparedStatement接口在Statement中可以看到,動態(tài)SQL的生成是通過字符串拼接而成的,但是字符串拼接會帶來很多的安全隱患,其中最為常見的安全漏洞就是SQL注入。下面以登錄功能為例,在.zzti.dao包下的UserDAO接口中定義登錄判斷方法,代碼如下:publicUserDOfindUser(Stringusername,Stringpassword)throwsSQLException;具體代碼如下:6.2.2SQL的執(zhí)行(2)java.sql.Prepa6.2.2SQL的執(zhí)行在代碼的第6行,我們將拼接后的SQL語句打印到控制臺進行觀察。在第12行處,需要將獲得的數(shù)據(jù)庫查詢結果進行封裝,這里暫不實現(xiàn)這個功能。下面先來創(chuàng)建一個.zzti.dao.impl.mysql.

jdbc.test.UserDAOImplTest類,對方法findUser進行測試,具體代碼如下。1publicUserDOfindUser(Stringusername,Stringpassword)throwsSQLException{2 Stringsql="select*fromuserwhereusername='"+3 username+4 "'andpassword='"+5 password+"'";6 System.out.println("登錄sql是:"+sql);7 Connectionconn=DBUtil.getConnection();8 Statementst=conn.createStatement();9 ResultSetrs=st.executeQuery(sql);10 if(rs.next()){11 UserDOuser=newUserDO();12 //將查詢結果封裝到user對象中,此處先不處理13 returnuser;14 }15 returnnull;16 }6.2.2SQL的執(zhí)行1publicUserDO6.2.2SQL的執(zhí)行Assert.assertNotNull(Objecto)是Junit的斷言,該斷言方法判斷對象o是否為空,為空則當前測試方法通過,否則測試方法失敗。執(zhí)行結果顯示,使用不存在的用戶名和密碼,調用登錄方法執(zhí)行結果為登錄正常。在輸出的SQL結果顯示,最終執(zhí)行的SQL如下:

1publicclassUserDAOImplTest{2 privateUserDAOuserDAO=(UserDAO)3 DAOFactory.getDAO(".zzti.dao.impl.mysql.jdbc.UserDAOImpl");4 @Test5 publicvoidtestFinUser(){6 Stringusername="test'or1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論