JDBC介紹和它的相關DML操作

2020-08-08 20:20:54

JDBC介紹

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中提供的一個規範,基本都是介面和抽象類作爲父類別,具體的實現,是數據庫廠商去弄的,只不過這些廠商需要按照我的介面標準來實現
如果我們要想操作數據庫,就需要把廠商開發的實現類,匯入進來

JDBC使用步驟

第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();
		}
	}

1 DML

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();
		}
	}

DQL

使用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();
		}
	}
}

PreparedStatement

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();
		}
	}
}

Batch多語句操作

在一次任務中,執行多條數據

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);
	}