JDBC定義了一套規範標準,它對應的是各種介面與抽象類(通常對應java.sql包下面 下麪的各種類與介面),具體實現交給各數據庫廠商去完成, MySQL的有自己的實現類並打成jar包發佈,供程式開發人員使用;Oracle也有自己的實現jar包。
我們開發人員在使用的時候,要根據連線數據庫的不同,去對應的官網上下載對應數據庫版本與程式語言的數據庫驅動(Java語言對應的是一個jar包)。(比如我們使用MySQL 5.1,就要去MySQL官網下載Java語言對應的jar包)
JDBC : Java DataBase Connectivity (java數據庫鏈接)
是讓java鏈接數據庫的API
API : Application Programming Intergace (應用程式介面)
就是函數庫
所以 JDBC 就是提供java連線數據庫的應用程式介面的,只是介面或者抽象類
而JDBC就是java中提供的一個規範,基本都是介面和抽象類作爲父類別,具體的實現,是數據庫廠商去弄的,只不過這些廠商需要按照我的介面標準來實現
如果我們要想操作數據庫,就需要把廠商開發的實現類,匯入進來
第0步: 導包
第1步:註冊驅動 (僅僅做一次)
第2步:建立連線(Connection)
第3步:建立執行SQL的語句(Statement)
第4步:執行語句
第5步:處理執行結果(ResultSet)
第6步:釋放資源
其中 如果是新增,刪除,更新操作,可以沒有第5步,查詢肯定會有第五步
上面程式中,有可能會導致釋放資源出現問題
比如查詢語句寫錯了等,這時候會拋出異常,那麼關閉語句就不會執行
所以我們應該使用try…catch…finally來優化一下
以剛纔的練習爲例,對test_jdbc表的查詢進行優化
Connection conn = null;
Statement stmt = null;
ResultSet rs = null ;
try {
// 1 載入驅動
Class.forName("com.mysql.jdbc.Driver");
// 2 建立數據庫連線物件
// 導包使用的都是java.sql的
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/_06_", "root", "root");
// 3 建立語句傳輸物件
String sql = "select * from test_jdbc";
stmt = conn.createStatement();
// 4 接收數據庫結果集
rs = stmt.executeQuery(sql);
while (rs.next()) {
// 在回圈遍歷中,把數據取出來
System.out.print(rs.getInt("id") + " ");
System.out.print(rs.getString("name") + " ");
System.out.println(rs.getDouble("money")+" ");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
Data Manipulation Language : 數據操作語言
涉及的關鍵字有 : delete,update,insert
和查詢的操作幾乎一樣,就是把第4步和第5步更改一下
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1 載入驅動
Class.forName("com.mysql.jdbc.Driver");
// 2 建立數據庫連線物件
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/_06_", "root", "root");
// 3 語句傳輸物件
stmt = conn.createStatement();
String sql = "insert into test_jdbc (id,name,money) values (4,'小小',999.9)";
// sql = "update test_jdbc set money=money+1000 where id=1 ";
// sql = "delete from test_jdbc where id = 1";
// 如果是查詢,就返回true,不是就返回false,價值不大,所以用的不多,新增,刪除,更新都可以用這個方法
// stmt.execute(sql);
// 返回值是int,返回影響了幾條數據(更改了幾條/刪除了幾條/新增了幾條),新增,刪除,更新都可以用這個方法
int count = stmt.executeUpdate(sql);
System.out.println("影響了 " + count + " 條數據");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關閉資源,從上到下依次關閉,後開啓的先關閉
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
使用PreparedStatement 執行查詢
public static void load(int id) {
Connection conn = null;
PreparedStatement prst = null;
ResultSet rs = null;
try {
// 1 載入驅動
Class.forName("com.mysql.jdbc.Driver");
// 2 建立數據庫連線物件
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/_06_", "root", "root");
// 這裏我們用? 問號代替值,可以叫佔位符,也可以叫萬用字元
String sql = "select * from test_jdbc where id = ?";
// 3 語句傳輸物件
prst = conn.prepareStatement(sql);
// 設定第一個?的值
prst.setInt(1, id);
rs = prst.executeQuery();
while (rs.next()) {
System.out.print(rs.getInt("id") + " ");
System.out.print(rs.getString("name") + " ");
System.out.println(rs.getString("money") + " ");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關閉資源,從上到下依次關閉,後開啓的先關閉
if (rs != null) {
rs.close();
}
if (prst != null) {
prst.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
Statement 和 PreparedStatement 的區別
Statement用於執行靜態SQL語句,在執行的時候,必須指定一個事先準備好的SQL語句,並且相對不安全,會有SQL隱碼攻擊的風險
PreparedStatement是預編譯的SQL語句物件,sql語句被預編譯並儲存在物件中, 被封裝的sql語句中可以使用動態包含的參數 ? ,
在執行的時候,可以爲?傳遞參數
使用PreparedStatement物件執行sql的時候,sql被數據庫進行預編譯和預解析,然後被放到緩衝區,
每當執行同一個PreparedStatement物件時,他就會被解析一次,單不會被再次編譯 可以重複使用,可以減少編譯次數,提高數據庫效能
並且能夠避免SQL隱碼攻擊,相對安全
PreparedStatement 的DML
使用PreparedStatement 執行增刪改,以新增爲例
public static void add(int id, String name, double money) {
Connection conn = null;
PreparedStatement prst = null;
try {
// 1 載入驅動
Class.forName("com.mysql.jdbc.Driver");
// 2 建立數據庫連線物件
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/_06_", "root", "root");
// 這裏我們用? 問號代替值,可以叫佔位符,也可以叫萬用字元
String sql = "insert into test_jdbc (id,name,money) values (?,?,?)";
// 3 語句傳輸物件
prst = conn.prepareStatement(sql);
// 設定第一個?的值
prst.setInt(1, id);
prst.setString(2, name);
prst.setDouble(3, money);
// 返回也是影響的條數
int count = prst.executeUpdate();
System.out.println("影響了 "+count+" 條數據");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關閉資源,從上到下依次關閉,後開啓的先關閉
if (prst != null) {
prst.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
建立鏈接這些可以這樣進行優化
public static Connection getConnection() throws ClassNotFoundException,
SQLException {
String username = 「root」;
String password = 「root」;
String url = 「jdbc:mysql://127.0.0.1:3306/06」;
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username,
password);
return connection;
}
關閉資源這些可以這樣進行優化
因爲Connection和Statement/PreparedStatement以及ResultSet都實現了AutoCloseable介面
所以我們可以直接寫AutoCloseable
public static void close(AutoCloseable obj) {
if (obj != null) {
try {
obj.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在一次任務中,執行多條數據
Statement實現
Connection conn = null;
Statement stmt = null;
try {
conn = DBUtil.getConnection();
stmt = conn.createStatement();
stmt.addBatch("insert into test_jdbc (id,name,money) values(21,'stmt多條測試1',99.12)");
stmt.addBatch("insert into test_jdbc (id,name,money) values(22,'stmt多條測試2',99.22)");
stmt.addBatch("insert into test_jdbc (id,name,money) values(23,'stmt多條測試3',99.32)");
stmt.addBatch("insert into test_jdbc (id,name,money) values(24,'stmt多條測試4',99.42)");
stmt.executeBatch();
System.out.println("執行成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(stmt);
DBUtil.close(conn);
}
PreparedStatement實現
Connection conn = null;
PreparedStatement prst = null;
try {
conn = DBUtil.getConnection();
String sql = "insert into test_jdbc (id,name,money) values(?,?,?)";
prst = conn.prepareStatement(sql);
prst.setInt(1, 31);
prst.setString(2, "prst多條測試1");
prst.setDouble(3, 11.1);
prst.addBatch();
prst.setInt(1, 32);
prst.setString(2, "prst多條測試2");
prst.setDouble(3, 21.1);
prst.addBatch();
prst.setInt(1, 33);
prst.setString(2, "prst多條測試3");
prst.setDouble(3, 31.1);
prst.addBatch();
prst.executeBatch();
System.out.println("執行成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(prst);
DBUtil.close(conn);
}