第一章:JDBC 概述
第一節:JDBC 簡介
JDBC(Java Data Base Connectivity,java 數據庫連接)是一種用於執行 SQL 語句的 JavaAPI,可以為多種關系 數據庫提供統一訪問,它由一組用 Java 語言編寫的類和接口組成。JDBC 提供了一種基准,據此可以構建更高 級的工具和接口,使數據庫開發人員能夠編寫數據庫應用程序。
第二節:JDBC 原理
JDBC 原理:JDBC 是以前 SUN 公司定義的一套訪問數據庫的接口(沒有具體實現),一套標准,具體的實現是由 各大數據庫廠家去實現,每個數據庫廠家都有自己的 JDBC 實現,也就是 JDBC 驅動實現類,Java 應用程序連接 指定數據庫,需要使用廠家提供的 JDBC 驅動才能連接。(這里其實就是 java 多態的一種體現,一個接口可以有 很多具體的實現)
第二章:JDBC 連接數據庫
第一節:JDBC 連接數據庫步驟
第一步:加載驅動;
第二步:連接數據庫;
第三步:使用語句操作數據庫;
第四步:關閉數據庫連接,釋放資源;
第二節:在項目里配置數據庫驅動
右擊項目 -> Build Path -> Configure Build Path -> Add Exteranl JARs..
第三節:加載數據驅動
Mysql 驅動名:com.mysql.jdbc.Driver
加載方式: Class.forName(驅動名);即Class.forName("com.mysql.jdbc.Driver");
第四節:連接及關閉數據庫
1,DriverManager 驅動管理類,主要負責獲取一個數據庫的連接;
static Connection getConnection(String url, String user, String password) 試圖建立到給定數據庫 URL 的連 接。
例如Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_book", "root", "123456");
2,MySQL 數據庫的連接地址格式
jdbc:mysql://IP 地址:端口號/數據庫名稱
jdbc 協議:JDBC
URL 中的協議總是 jdbc ;
子協議:驅動程序名或數據庫連接機制(這種機制可由一個或多個驅動程序支持)的名稱,如 mysql; 子
名稱:一種標識數據庫的方法。必須遵循“//主機名端口/子協議”的標准 URL 命名約定,如 //localhost:3306/db_book3,Connection 接口 與特定數據庫的連接(會話)。
void close() 立即釋放此 Connection 對象的數據庫和 JDBC 資源,而不是等待它們被自動釋放
第三章:使用 Statement 接口實現增,刪,改操作
作用:用於執行靜態 SQL 語句並返回它所生成結果的對象。
利用Statement stmt=con.createStatement(); 獲取Statement對象。
int executeUpdate(String sql) 執行給定 SQL 語句,該語句可能為 INSERT、UPDATE 或DELETE 語句,或 者不返回任何內容的 SQL 語句(如 SQL DDL 語句)。
void close() 立即釋放此 Statement 對象的數據庫和 JDBC 資源,而不是等待該對象自動關閉時發生此操作。
注:1.可以將Statemant與Connection的close寫在一個方法中
如:
public void close(Statement stmt,Connection con)throws Exception{ if(stmt!=null){ stmt.close(); if(con!=null){ con.close(); } } }
2.stmt.executeUpdate(sql);會返回一個int類型的result,可以用這個判斷是否語句是否成功,成功的話會返回1。
第四章:使用 PreparedStatement 接口實現增,刪,改操作
PreparedStatement 是 Statement 的子接口,屬於預處理操作,與直接使用 Statement 不同的是,PreparedStatement 在操作時,是先在數據表中准備好了一條 SQL 語句,但是此 SQL 語句的具體內容暫時不設置,而是之后再進 行設置。
(以后開發一般用 PreparedStatement,不用 Statement)
寫入數據時可以這么做
private static int addBook(Book book)throws Exception{
Connection con=dbUtil.getCon(); // 獲取連接
String sql="insert into t_book values(null,?,?,?,?)";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setString(1, book.getBookName()); // 給第一個坑設置值
pstmt.setFloat(3, book.getPrice()); // 給第二個坑設置值
pstmt.setString(2, book.getAuthor()); // 給第三個坑設置值
pstmt.setInt(4, book.getBookTypeId()); // 給第四個坑設置值
int result=pstmt.executeUpdate();
dbUtil.close(pstmt, con);
return result;
}
第五章: ResultSet 結果集
第一節:ResultSet 結果集的引入
當我們查詢數據庫時,返回的是一個二維的結果集,我們這時候需要使用 ResultSet 來遍歷結果集,獲取每一行 的數據。
第二節:使用 ResultSet 遍歷查詢結果
boolean next() 將光標從當前位置向前移一行。 String getString(int columnIndex) 以 Java 編程語言中 String 的形式獲取此 ResultSet 對象的當前行中指定列 的值。 String getString(String columnLabel) 以 Java 編程語言中 String 的形式獲取此 ResultSet 對象的當前行中指 定列的值。
讀取數據時可以分別以這三種形式:利用index,關鍵字,或者直接獲取一個對象。
private static void listBook() throws Exception { Connection con = dbUtil.getCon(); // 獲取連接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回結果集ResultSet//默認在第0行 while (rs.next()) { int id = rs.getInt(1); // 獲取第一個列的值 編號id String bookName = rs.getString(2); // 獲取第二個列的值 圖書名稱 bookName float price = rs.getFloat(4); // 獲取第三列的值 圖書價格 price String author = rs.getString(3); // 獲取第四列的值 圖書作者 author int bookTypeId = rs.getInt(5); // 獲取第五列的值 圖書類別id System.out.println("圖書編號:" + id + " 圖書名稱:" + bookName + " 圖書價格:" + price + " 圖書作者:" + author + " 圖書類別id:" + bookTypeId); System.out .println("======================================================================="); } }
private static void listBook2() throws Exception { Connection con = dbUtil.getCon(); // 獲取連接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回結果集ResultSet while (rs.next()) { int id = rs.getInt("id"); // 獲取第一個列的值 編號id String bookName = rs.getString("bookName"); // 獲取第二個列的值 圖書名稱 bookName float price = rs.getFloat("price"); // 獲取第三列的值 圖書價格 price String author = rs.getString("author"); // 獲取第四列的值 圖書作者 author int bookTypeId = rs.getInt("bookTypeId"); // 獲取第五列的值 圖書類別id System.out.println("圖書編號:" + id + " 圖書名稱:" + bookName + " 圖書價格:" + price + " 圖書作者:" + author + " 圖書類別id:" + bookTypeId); System.out .println("======================================================================="); } }
private static List<Book> listBook3()throws Exception{ List<Book> bookList=new ArrayList<Book>(); Connection con = dbUtil.getCon(); // 獲取連接 String sql = "select * from t_book"; PreparedStatement pstmt = con.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); // 返回結果集ResultSet while (rs.next()) { int id = rs.getInt("id"); // 獲取第一個列的值 編號id String bookName = rs.getString("bookName"); // 獲取第二個列的值 圖書名稱 bookName float price = rs.getFloat("price"); // 獲取第三列的值 圖書價格 price String author = rs.getString("author"); // 獲取第四列的值 圖書作者 author int bookTypeId = rs.getInt("bookTypeId"); // 獲取第五列的值 圖書類別id Book book=new Book(id, bookName, price, author, bookTypeId); bookList.add(book); } return bookList; }
第六章: 處理大數據對象
大數據對象處理主要有 CLOB(character large object)和 BLOB(binary large object)兩種類型的字段;在 CLOB 中可以存儲大字符數據對象,比如長篇小說;在 BLOB 中可以存放二進制大數據對象,比如圖片,電影,音樂;
第一節:處理 CLOB 數據
package com.java1234.jdbc.chap06.sec01; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.sql.Clob; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.java1234.jdbc.model.Book; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 添加圖書 * @param book * @return * @throws Exception */ private static int addBook(Book book)throws Exception{ Connection con=dbUtil.getCon(); // 獲取連接 String sql="insert into t_book values(null,?,?,?,?,?)"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); // 給第一個坑設置值 pstmt.setFloat(3, book.getPrice()); // 給第二個坑設置值 pstmt.setString(2, book.getAuthor()); // 給第三個坑設置值 pstmt.setInt(4, book.getBookTypeId()); // 給第四個坑設置值 File context=book.getContext(); // 獲取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 給第五個坑設置值 int result=pstmt.executeUpdate(); dbUtil.close(pstmt, con); return result; } public static void getBook(int id)throws Exception{ Connection con=dbUtil.getCon(); String sql="select * from t_book where id=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, id); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ String bookName=rs.getString("bookName"); float price=rs.getFloat("price"); String author=rs.getString("author"); int bookTypeId=rs.getInt("bookTypeId"); Clob c=rs.getClob("context"); String context=c.getSubString(1, (int) c.length()); System.out.println("圖書名稱:"+bookName); System.out.println("圖書價格:"+price); System.out.println("圖書作者:"+author); System.out.println("圖書類型ID:"+bookTypeId); System.out.println("圖書內容:"+context); } dbUtil.close(pstmt, con); } public static void main(String[] args)throws Exception { // String str="C:\\152.txt"; // String location=str.replace("\\\\", "/"); // File context=new File(location); // System.out.println(location); // Book book=new Book("helloWorld", 100, "小鋒", 1,context); // int result=addBook(book); // if(result==1){ // System.out.println("添加成功!"); // }else{ // System.out.println("添加失敗!"); // } getBook(6); } }
第二節:處理 BLOG 數據
package com.java1234.jdbc.chap06.sec02; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.java1234.jdbc.model.Book; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 添加圖書 * @param book * @return * @throws Exception */ private static int addBook(Book book)throws Exception{ Connection con=dbUtil.getCon(); // 獲取連接 String sql="insert into t_book values(null,?,?,?,?,?,?)"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1, book.getBookName()); // 給第一個坑設置值 pstmt.setFloat(3, book.getPrice()); // 給第二個坑設置值 pstmt.setString(2, book.getAuthor()); // 給第三個坑設置值 pstmt.setInt(4, book.getBookTypeId()); // 給第四個坑設置值 File context=book.getContext(); // 獲取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 給第五個坑設置值 File pic=book.getPic(); // 獲取圖片文件 InputStream inputStream2=new FileInputStream(pic); pstmt.setBinaryStream(6, inputStream2, (int)pic.length()); // 給第六個坑設置值 int result=pstmt.executeUpdate(); dbUtil.close(pstmt, con); return result; } public static void getBook(int id)throws Exception{ Connection con=dbUtil.getCon(); String sql="select * from t_book where id=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, id); ResultSet rs=pstmt.executeQuery(); if(rs.next()){ String bookName=rs.getString("bookName"); float price=rs.getFloat("price"); String author=rs.getString("author"); int bookTypeId=rs.getInt("bookTypeId"); Clob c=rs.getClob("context"); String context=c.getSubString(1, (int)c.length()); Blob b=rs.getBlob("pic"); FileOutputStream out=new FileOutputStream(new File("d:/pic2.jpg")); out.write(b.getBytes(1, (int)b.length())); out.close(); System.out.println("圖書名稱:"+bookName); System.out.println("圖書價格:"+price); System.out.println("圖書作者:"+author); System.out.println("圖書類型ID:"+bookTypeId); System.out.println("圖書內容:"+context); } dbUtil.close(pstmt, con); } public static void main(String[] args)throws Exception { // String str="C:\\152.txt"; // String location=str.replace("\\\\", "/"); // File context=new File(location); // String str1="C:\\123.jpg"; // String str2=str1.replace("\\\\", "/"); // File pic=new File(str2); // Book book=new Book("helloWorld", 100, "小鋒", 1,context,pic); // int result=addBook(book); // if(result==1){ // System.out.println("添加成功!"); // }else{ // System.out.println("添加失敗!"); // } getBook(11); } }
注意:1.利用下面這種方式對文件進行讀取,防止目錄出現問題,一般出現問題,除了是文件名錯誤外,還有就是復制會帶來額外的東西,我們需要手打。
String str="C:\\152.txt"; String location=str.replace("\\\\", "/"); File context=new File(location);
2.寫入數據時,注意第三行的第三個值要強轉成int類型,而且對於CLOG數據,使用setAsciiStream,對於BLOG 數據,要使用setBinaryStream進行寫入
File context=book.getContext(); // 獲取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length());
File context=book.getContext(); // 獲取文件 InputStream inputStream=new FileInputStream(context); pstmt.setAsciiStream(5, inputStream,(int)context.length()); // 給第五個坑設置值 File pic=book.getPic(); // 獲取圖片文件 InputStream inputStream2=new FileInputStream(pic); pstmt.setBinaryStream(6, inputStream2, (int)pic.length()); // 給第六個坑設置值
3.讀取數據時,對於CLOG數據,用下面這種方法。
Clob c=rs.getClob("context"); String context=c.getSubString(1, (int) c.length());
對於BLOG 數據,用接下來這種方法,也就是直接寫成多媒體格式。
Blob b=rs.getBlob("pic"); FileOutputStream out=new FileOutputStream(new File("d:/pic2.jpg")); out.write(b.getBytes(1, (int)b.length())); out.close();
第七章: 使用 CallableStatement 接口調用存儲過程
CallableStatement 主要是調用數據庫中的存儲過程,CallableStatement 也是 PreparedStatement 接口的子接口。在使用 CallableStatement 時可以接收存儲過程的返回值。
void registerOutParameter(int parameterIndex, int sqlType) 按順序位置 parameterIndex 將 OUT 參數注冊為 JDBC 類型 sqlType。
private static String getBookNameById(int id)throws Exception{ Connection con=dbUtil.getCon(); // 獲取數據庫連接 String sql="{CALL pro_getBookNameById1(?,?)}"; CallableStatement cstmt=con.prepareCall(sql); cstmt.setInt(1, id); // 設置第一個參數 cstmt.registerOutParameter(2, Types.VARCHAR); // 設置返回類型 cstmt.execute(); String bookName=cstmt.getString(1); // 獲取返回值//這里不僅可以利用index,利用關鍵字也可以。 dbUtil.close(cstmt, con); return bookName; }
注意:sql語句外的大括號。
第八章: 使用元數據分析數據庫
第一節:使用 DatabaseMetaData 獲取數據庫基本信息
DatabaseMetaData 可以得到數據庫的一些基本信息,包括數據庫的名稱、版本,以及得到表的信息。
String getDatabaseProductName() 獲取此數據庫產品的名稱。 int getDriverMajorVersion() 獲取此 JDBC 驅動程序的主版本號。
int getDriverMinorVersion() 獲取此 JDBC 驅動程序的次版本號。
public static void main(String[] args)throws Exception { DbUtil dbUtil=new DbUtil(); Connection con=dbUtil.getCon(); DatabaseMetaData dmd=con.getMetaData(); // 獲取元數據 System.out.println("數據庫名稱:"+dmd.getDatabaseProductName()); System.out.println("數據庫版本:"+dmd.getDriverMajorVersion()+"."+dmd.getDriverMinorVersion()); }
第二節:使用 ResultSetMetaData 獲取 ResultSet
ResultSetMetaData 可獲取關於 ResultSet 對象中列的基本信息;
int getColumnCount() 返回此 ResultSet 對象中的列數。
String getColumnName(int column) 獲取指定列的名稱。
int getColumnTypeName(int column) 獲取指定列的 SQL 類型名稱。
public static void main(String[] args) throws Exception{ DbUtil dbUtil=new DbUtil(); Connection con=dbUtil.getCon(); String sql="select * from t_book"; PreparedStatement pstmt=con.prepareStatement(sql); ResultSetMetaData rsmd=pstmt.getMetaData(); int num=rsmd.getColumnCount(); // 獲取元數據列的總數 for(int i=1;i<=num;i++){ System.out.println(rsmd.getColumnName(i)+","+rsmd.getColumnTypeName(i)); } }
第九章: JDBC 事務處理
第一節:事務的概念
事務處理在數據庫開發中有着非常重要的作用,所謂事務就是所有的操作要么一起成功,要么一起失敗,事務 本身具有原子性(Atomicity)、一致性(Consistency)、隔離性或獨立性(Isolation)、持久性(Durability)4 個特 性,這 4 個特性也被稱為 ACID 特征。
原子性:原子性是事務最小的單元,是不可再分隔的單元,相當於一個個小的數據庫操作,這些操作必須同時 成功,如果一個失敗了,則一切的操作將全部失敗。
一致性:指的是在數據庫操作的前后是完全一致的,保證數據的有效性,如果事務正常操作則系統會維持有效 性,如果事務出現了錯誤,則回到最原始狀態,也要維持其有效性,這樣保證事務開始時和結束時系統處於一 致狀態。
隔離性:多個事務可以同時進行且彼此之間無法訪問,只有當事務完成最終操作時,才可以看到結果;
持久性:事務完成之后,它對於系統的影響是永久性的。該修改即使出現致命的系統故障也將一直保持。
package com.java1234.jdbc.chap09.sec04; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Savepoint; import com.java1234.jdbc.util.DbUtil; public class Demo1 { private static DbUtil dbUtil=new DbUtil(); /** * 轉出 * @param con * @param accountName * @param account * @throws Exception */ private static void outCount(Connection con,String accountName,int account)throws Exception{ String sql="update t_account set accountBalance=accountBalance-? where accountName=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, account); pstmt.setString(2, accountName); pstmt.executeUpdate(); } /** * 轉入 * @param con * @param accountName * @param account * @throws Exception */ private static void inCount(Connection con,String accountName,int account)throws Exception{ String sql="update t_account set account=accountBalance+? where accountName=?"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setInt(1, account); pstmt.setString(2, accountName); pstmt.executeUpdate(); } public static void main(String[] args) { Connection con=null; Savepoint sp=null; try { con=dbUtil.getCon(); con.setAutoCommit(false); // 取消自動提交 System.out.println("張三開始向李四轉賬!"); int account=500; outCount(con, "張三", account); //sp=con.setSavepoint(); // 設置一個保存點 inCount(con, "李四", account); System.out.println("轉賬成功!"); } catch (Exception e) { try { con.rollback(); // 回滾到sp保存點 } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { con.commit(); // 提交事務 con.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
第二節:MySQL 對事務的支持