本文目錄
學習小結
1、JDBC簡介
2、使用JDBC的步驟——第一個JDBC程序
3、DriverManager ——加載數據庫驅動
4、數據庫URL ——標識數據庫的位置
5、Connection ——代表數據庫的鏈接
6、Statement ——向數據庫發送SQL語句
7、ResultSet ——代表Sql語句的執行結果
8、釋放資源 ——釋放與數據庫進行交互的對象
9、用JDBC對數據庫進行CRUD
10、CRUD操作-create 示例Demo
11、CRUD操作-updata 示例Demo
12、CRUD操作-delete 示例Demo
13、CRUD操作-read 示例Demo
14、SQL 注入的防範
15、PreparedStatement
16、數據庫分頁——實現語句
17、數據庫分頁—— 採用Dao工廠模式實現數據庫分頁原理圖解
18、數據庫分頁——執行流程中所需的類及代碼
19、數據庫分頁——QueryInfo類、PageBean類、QueryResult類 三個輔助類的內容
相關學習
JDBC 學習筆記(一)—— 基礎知識 + 分頁技術
鏈接地址:http://even2012.iteye.com/blog/1886946
JDBC 學習筆記(二)—— 大數據+存儲過程+批處理+事務
鏈接地址:http://even2012.iteye.com/blog/1886950
JDBC 學習筆記(三)—— 數據源(數據庫連接池):DBCP數據源、C3P0 數據源以及自定義數據源技術
鏈接地址:http://even2012.iteye.com/blog/1886953
JDBC 學習筆記(四)—— 自定義JDBC框架+Apache—DBUtils框架+事務管理+操作多表
鏈接地址:http://even2012.iteye.com/blog/1886956
學習小結
1、JDBC簡介
SUN公司爲了簡化、統一對數據庫的操作,定義了一套Java操作數據庫的規範,稱之爲JDBC。
JDBC全稱爲:Java Data Base Connectivity(java數據庫連接),它主要由接口組成。
組成JDBC的2個包:
java.sql
javax.sql
開發JDBC應用需要以上2個包的支持外,還需要導入相應JDBC的數據庫實現(即數據庫驅動)。
2、使用JDBC的步驟——第一個JDBC程序
需求:編程從user表中讀取數據,並打印在命令行窗口中。
(1) 搭建實驗環境 :
a、在mysql中創建一個庫,並創建user表t同時插入數據到表中。
b、新建一個Java工程,並導入數據庫驅動。
(2) 編寫程序,在程序中加載數據庫驅動
a、方式一:DriverManager. registerDriver(Driver driver)
b、方式二:Class.forName(“com.mysql.jdbc.Driver”);
(3) 建立連接(Connection)
Connection conn = DriverManager.getConnection(url,user,pass);
(4) 創建用於向數據庫發送SQL的Statement對象,併發送sql
Statement st = conn.createStatement();
ResultSet rs = st.excuteQuery(sql);
(5) 從代表結果集的ResultSet中取出數據,打印到命令行窗口
(6) 斷開與數據庫的連接,並釋放相關資源
Demo樣例:
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/day14";
String username = "root";
String password = "root";
//1.加載驅動
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2。獲取鏈接
Connection conn = DriverManager.getConnection(url, username, password);
//3.獲取向數據庫發sql語句的statament對象
Statement st = conn.createStatement();
//4.向數據庫發送sql,獲取數據庫返回的結果集
ResultSet rs = st.executeQuery("select * from users");
//5.從結果集中獲取數據
while(rs.next()){
System.out.println("id=" + rs.getObject("id"));
System.out.println("name=" + rs.getObject("name"));
System.out.println("password=" + rs.getObject("password"));
System.out.println("email=" + rs.getObject("email"));
System.out.println("birthday=" + rs.getObject("birthday"));
}
//6.釋放資源(釋放鏈接)
rs.close();
st.close();
conn.close();
}
3、DriverManager ——加載數據庫驅動
Jdbc程序中的DriverManager用於加載驅動,並創建與數據庫的鏈接,這個API的常用方法:
DriverManager.registerDriver(new Driver())
DriverManager.getConnection(url, user, password),
注意:在實際開發中並不推薦採用registerDriver方法註冊驅動。原因有二:
一、查看Driver的源代碼可以看到,如果採用此種方式,會導致驅動程序註冊兩次,也就是在內存中會有兩個Driver對象。
二、程序依賴mysql的api,脫離mysql的jar包,程序將無法編譯,將來程序切換底層數據庫將會非常麻煩。
推薦方式:Class.forName(“com.mysql.jdbc.Driver”);
採用此種方式不會導致驅動對象在內存中重複出現,並且採用此種方式,程序僅僅只需要一個字符串,不需要依賴具體的驅動,使程序的靈活性更高。
同樣,在開發中也不建議採用具體的驅動類型指向getConnection方法返回的connection對象。
Demo:數據庫JDBC開發使用的模版(Statement對象。):
String url = "jdbc:mysql:///day14";
String username = "root";
String password = "root";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
st = conn.createStatement(); //throw
CRUD操作……
}finally{
if(rs!=null){
try{
rs.close(); //throw new
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
st = null;
}
if(conn!=null){
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
4、數據庫URL ——標識數據庫的位置
URL用於標識數據庫的位置,程序員通過URL地址告訴JDBC程序連接哪個數據庫,
MySql 數據庫的URL寫法爲: jdbc:mysql:[]//localhost:3306/test ?參數名:參數值
URL圖解
常用數據庫URL地址的寫法:
Oracle寫法:jdbc:oracle:thin:@localhost:1521:sid
SqlServer—jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid
MySql—jdbc:mysql://localhost:3306/sid
Mysql的url地址的簡寫形式: jdbc:mysql:///sid
常用屬性:useUnicode=true&characterEncoding=UTF-8
5、Connection ——代表數據庫的鏈接
Jdbc程序中的Connection,它用於代表數據庫的鏈接。Connection 是數據庫編程中最重要的一個對象,客戶端與數據庫所有交互都是通過Connection 對象完成的,這個對象的常用方法:
(1) createStatement():創建向數據庫發送sql的statement對象。
(2) prepareStatement(sql) :創建向數據庫發送預編譯sql的PrepareSatement對象。
(3) prepareCall(sql):創建執行存儲過程的callableStatement對象。
(4) setAutoCommit(boolean autoCommit):設置事務是否自動提交。
(5) commit() :在鏈接上提交事務。
(6) rollback() :在此鏈接上回滾事務。
6、Statement ——向數據庫發送SQL語句
Jdbc程序中的Statement對象用於向數據庫發送SQL語句, Statement對象常用方法:
(1) executeQuery(String sql) :用於向數據庫發送查詢語句。
(2) executeUpdate(String sql):用於向數據庫發送insert、update或delete語句
(3) execute(String sql):用於向數據庫發送任意sql語句
(4) addBatch(String sql) :把多條sql語句放到一個批處理中。
(5) executeBatch():向數據庫發送一批sql語句執行。
(6) clearBatch() :清空此 Statement 對象的當前 SQL 命令列表。
7、ResultSet ——代表Sql語句的執行結果
Jdbc程序中的ResultSet用於代表Sql語句的執行結果。Resultset封裝執行結果時,採用的類似於表格的方式。ResultSet 對象維護了一個指向表格數據行的遊標,初始的時候,遊標在第一行之前,調用ResultSet.next() 方法,可以使遊標指向具體的數據行,進行調用方法獲取該行的數據。
(1) ResultSet提供了對結果集進行滾動的方法:
a、next():移動到下一行
b、Previous():移動到前一行
c、absolute(int row):移動到指定行
d、beforeFirst():移動resultSet的最前面。
e、 afterLast() :移動到resultSet的最後面。
(2) ResultSet既然用於封裝執行結果的,所以該對象提供了用於獲取數據的get方法:
獲取任意類型的數據
getObject(int index)
getObject(string columnName)
獲取指定類型的數據,例如:
getString(int index)
getString(String columnName)
其他獲取指定類型數據的方法見下表:
常用數據類型轉換表
8、釋放資源 ——釋放與數據庫進行交互的對象
Jdbc程序運行完後,切記要釋放程序在運行過程中,創建的那些與數據庫進行交互的對象,這些對象通常是ResultSet, Statement和Connection對象。
特別是Connection對象,它是非常稀有的資源,用完後必須馬上釋放,如果Connection不能及時、正確的關閉,極易導致系統宕機。Connection的使用原則是儘量晚創建,儘量早的釋放。
爲確保資源釋放代碼能運行,資源釋放代碼也一定要放在finally語句中。
9、用JDBC對數據庫進行CRUD
Jdbc中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查語句即可。
Statement對象的executeUpdate方法,用於向數據庫發送增、刪、改的sql語句,executeUpdate執行完後,將會返回一個int整數(即增刪改語句導致了數據庫幾行數據發生了變化)。
Statement.executeQuery方法用於向數據庫發送查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象。
10、CRUD操作-create 示例Demo
使用executeUpdate(String sql)方法完成數據添加操作,示例操作:
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
Statement st = conn.createStatement();
String sql = "insert into user(….) values(…..) ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
11、CRUD操作-updata 示例Demo
使用executeUpdate(String sql)方法完成數據修改操作,示例操作:
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
Statement st = conn.createStatement();
String sql = “update user set name=‘ ’ where name=‘ ’ ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“修改成功!!!");
}
12、CRUD操作-delete 示例Demo
使用executeUpdate(String sql)方法完成數據刪除操作,示例操作:
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println(“刪除成功!!!");
}
13、CRUD操作-read 示例Demo
使用executeQuery(String sql)方法完成數據查詢操作,示例操作:
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
Statement st = conn.createStatement();
String sql = “select * from user where id=1 “;
ResultSet rs = st.executeUpdate(sql);
while(rs.next()){
//根據獲取列的數據類型,分別調用rs的相應方法
//映射到java對象中
}
14、SQL 注入的防範
SQL 注入是用戶利用某些系統沒有對輸入數據進行充分的檢查,從而進行惡意破壞的行爲。
1、statement存在sql注入攻擊問題,例如登陸用戶名採用' or 1=1 or username=‘
2、對於防範 SQL 注入,可以採用PreparedStatement取代Statement。
備註:本例只是最基本的防止SQL注入方式,其他情況還請查閱資料。
15、PreparedStatement
PreperedStatement是Statement的孩子,它的實例對象可以通過調用Connection.preparedStatement()方法獲得,相對於Statement對象而言的優勢:
(1) 防止SQL注入:PreperedStatement可以避免SQL注入的問題。
(2) 預編譯SQL語句:Statement會使數據庫頻繁編譯SQL,可能造成數據庫緩衝區溢出。PreparedStatement 可對SQL進行預編譯,從而提高數據庫的執行效率。
(3) 使用佔位符簡化語句:並且PreperedStatement對於sql中的參數,允許使用佔位符的形式進行替換,簡化sql語句的編寫。 (例如多次循環插入數據)
Demo樣例:
public List<Customer> getAll(){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "select * from customer";
st = conn.prepareStatement(sql);
rs = st.executeQuery();
List list = new ArrayList();
while(rs.next()){
Customer c = new Customer();
c.setBirthday(rs.getDate("birthday"));
c.setCellphone(rs.getString("cellphone"));
c.setDescription(rs.getString("description"));
c.setEmail(rs.getString("email"));
c.setGender(rs.getString("gender"));
c.setId(rs.getString("id"));
c.setName(rs.getString("name"));
c.setPreference(rs.getString("preference"));
c.setType(rs.getString("type"));
list.add(c);
}
return list;
}catch (Exception e) {
throw new DaoException(e);
}finally{
JdbcUtils.release(conn, st, rs);
}
}
16、數據庫分頁——實現語句
(1) MySQL分頁
MySQL分頁的實現語句:
Select * from table limit M,N
M:記錄開始索引位置
N:取多少條記錄。
完成WEB頁面的分頁顯示的步驟:
(a) 先獲得需分頁顯示的記錄總數,然後在web頁面中顯示頁碼。
(b) 根據頁碼,從數據庫中查詢相應的記錄顯示在web頁面中。
以上兩項操作通常使用Page對象進行封裝。
(2) Oracle分頁
Oracle分頁的實現語句:
select * from (
select rownum r_, row_.* from (
select * from student order by id
) row_ where rownum <=5
) where r_>=1
1位置:起始索引位置。
5位置:結束索引位置。
備註:關於Oracle的分頁,此處僅是簡單講解,會在Oracle 專題博文中詳述。
17、數據庫分頁—— 採用Dao工廠模式實現數據庫分頁原理圖解
(1) dao工廠模式的原理示意圖
(2) 數據庫分頁 原理圖解
18、數據庫分頁——執行流程中所需的類及代碼
(1)Servlet層:ListCustomerServlet .java
//處理用戶分頁請求
public class ListCustomerServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
QueryInfo info = WebUtils.request2Bean(request, QueryInfo.class);
BusinessService service = new BusinessServiceImpl();
PageBean pagebean = service.pageQuery(info);
request.setAttribute("pagebean", pagebean);
request.getRequestDispatcher("/WEB-INF/jsp/listcustomer.jsp").forward(request, response);
}catch (Exception e) {
e.printStackTrace();
request.setAttribute("message", "查看客戶失敗!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(2) Service層:BusinessServiceImpl.java
public class BusinessServiceImpl implements BusinessService {
public PageBean pageQuery(QueryInfo queryInfo){
//調用dao獲取到頁面數據
QueryResult qr = dao.pageQuery(queryInfo.getStartindex(), queryInfo.getPagesize());
//根據dao查詢結果,生成頁面顯示需要pagebean
PageBean bean = new PageBean();
bean.setCurrentpage(queryInfo.getCurrentpage());
bean.setList(qr.getList());
bean.setPagesize(queryInfo.getPagesize());
bean.setTotalrecord(qr.getTotalrecord());
return bean;
}
}
(3)Dao層:CustomerDaoImpl.java
public class CustomerDaoImpl implements CustomerDao {
//獲取到頁面數據和頁面大小
public QueryResult pageQuery(int startindex,int pagesize){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
QueryResult qr = new QueryResult();
try{
conn = JdbcUtils.getConnection();
String sql = "select * from customer limit ?,?";
st = conn.prepareStatement(sql);
st.setInt(1, startindex);
st.setInt(2, pagesize);
rs = st.executeQuery();
List list = new ArrayList();
while(rs.next()){
Customer c = new Customer();
c.setBirthday(rs.getDate("birthday"));
c.setCellphone(rs.getString("cellphone"));
c.setDescription(rs.getString("description"));
c.setEmail(rs.getString("email"));
c.setGender(rs.getString("gender"));
c.setId(rs.getString("id"));
c.setName(rs.getString("name"));
c.setPreference(rs.getString("preference"));
c.setType(rs.getString("type"));
list.add(c);
}
qr.setList(list);
sql = "select count(*) from customer";
st = conn.prepareStatement(sql);
rs = st.executeQuery();
if(rs.next()){
qr.setTotalrecord(rs.getInt(1));
}
return qr;
}catch (Exception e) {
throw new DaoException(e);
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
19、數據庫分頁——QueryInfo類、PageBean類、QueryResult類 三個輔助類的內容
(1)QueryInfo.java 類中的內容:
public class QueryInfo {
private int currentpage = 1; //用戶當前看的頁
private int pagesize = 5; //記住用戶想看的頁面大小
private int startindex; //記住用戶看的頁的數據在數據庫的起始位置
public int getCurrentpage() {
return currentpage;
}
public void setCurrentpage(int currentpage) {
this.currentpage = currentpage;
}
public int getPagesize() {
return pagesize;
}
public void setPagesize(int pagesize) {
this.pagesize = pagesize;
}
public int getStartindex() {
this.startindex = (this.currentpage-1)*this.pagesize;
return startindex;
}
}
(2)PageBean.java 類中的內容:
public class PageBean {
private List list;
private int totalrecord;
private int pagesize;
private int totalpage;
private int currentpage;
private int previouspage;
private int nextpage;
private int[] pagebar;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public int getTotalrecord() {
return totalrecord;
}
public void setTotalrecord(int totalrecord) {
this.totalrecord = totalrecord;
}
public int getPagesize() {
return pagesize;
}
public void setPagesize(int pagesize) {
this.pagesize = pagesize;
}
public int getTotalpage() {
//100 5 20
//101 5 21
//99 5 20
if(this.totalrecord%this.pagesize==0){
this.totalpage = this.totalrecord/this.pagesize;
}else{
this.totalpage = this.totalrecord/this.pagesize+1;
}
return totalpage;
}
public int getCurrentpage() {
return currentpage;
}
public void setCurrentpage(int currentpage) {
this.currentpage = currentpage;
}
public int getPreviouspage() {
if(this.currentpage-1<1){
this.previouspage = 1;
}else{
this.previouspage = this.currentpage-1;
}
return previouspage;
}
public int getNextpage() {
if(this.currentpage+1>=this.totalpage){
this.nextpage = this.totalpage;
}else{
this.nextpage = this.currentpage +1;
}
return nextpage;
}
public int[] getPagebar() {
int startpage;
int endpage;
int pagebar[] = null;
if(this.totalpage<=10){
pagebar = new int[this.totalpage];
startpage = 1;
endpage = this.totalpage;
}else{
pagebar = new int[10];
startpage = this.currentpage - 4;
endpage = this.currentpage + 5;
//總頁數=30 3 -1
//總頁數=30 29 34 21 30
if(startpage<1){
startpage = 1;
endpage = 10;
}
if(endpage>this.totalpage){
endpage = this.totalpage;
startpage = this.totalpage - 9;
}
}
int index = 0;
for(int i=startpage;i<=endpage;i++){
pagebar[index++] = i;
}
this.pagebar = pagebar;
return this.pagebar;
/*int pagebar[] = new int[this.totalpage];
for(int i=1;i<=this.totalpage;i++){
pagebar[i-1] = i;
}
this.pagebar = pagebar;
return pagebar;*/
}
}
(3)QueryResult.java 類中的內容:
public class QueryResult {
private List list; //記住用戶看的頁的數據
private int totalrecord; //記往總記錄數
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public int getTotalrecord() {
return totalrecord;
}
public void setTotalrecord(int totalrecord) {
this.totalrecord = totalrecord;
}
}
敬請評論
(1)若您覺得本文 有用處 —— 請留言評論,以堅定其他 IT童鞋 閱讀本文的信心。
(2)若您覺得本文 沒用處 —— 請留言評論,筆者將會改進不足,以便爲大家整理更加好用的筆記。