先感謝前人的勞動成果,html
本教程中含有多處指路,請注意篩選.java
詳細請閱讀官方文檔:https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html (不建議直接上手)mysql
https://www.journaldev.com/2681/jdbc-tutorialsql
前置知識:基本SQL 語句,JAVA SE基礎數據庫
JDBC 目錄:apache
1.JDBC概念編程
2.JDBC處理SQL語句的過程(建表,查表) api
3.專題介紹服務器
4.結尾併發
1. JDBC的概念
JDBC(Java DataBase Connectivity)
是一種數據庫鏈接技術,
能實現Java程序對各類數據庫的訪問。由一組使用Java語言編寫的類和接口(JDBC API)
組成,他們位於java.sql以及javax.sql中。
推薦解釋指路 中的 (二.JDBC是什麼)
做用:
1. 與數據庫創建聯繫.
2. 將編寫好的SQL語句發送至數據庫執行
3. 對數據庫返回的結果進行操做
JDBC API
javax.sql.*
鏈接數據庫相關的:
DriverManager:
用URL鏈接數據庫,
在4.0版本以前要進行加載. 即用映射加載驅動 Class.forName("com.mysql.jdbc.Driver");
相對於DriverManager類,DataSource更適合用於獲取操做數據的Connection對象,
它相對靈活,而且支持 JNDI ,能夠爲servlet容器提供鏈接池
(能夠去找DBCP的資料,這裏涉及到了 The Java EE Tutorial.)
鏈接池解釋推薦指路,後續會解釋DataSource的使用.
Connection接口:
負責鏈接數據庫並擔任傳送數據的任務。
數據庫SQL相關的:
Statement接口:
負責執行SQL語句。
ResultSet接口:
負責保存Statement執行後所產生的查詢結果。
RowSet接口:
RowSet 比 ResultSet 功能更多,更易使用,全部的RowSet對象都繼承於 ResultSet.
2.JDBC處理SQL語句的過程(建表,查表)
使用JDBC 的步驟
這裏,咱們使用MySQL 進行演示,
若是你使用是JAVA DB,他自帶了JDBC
首先去MySQL官方下載 MYSQL 和 Connector/J.
(如下內容請根據本身環境進行配置)(官方教程使用的是 Apache ANT)
咱們要使用 Connector/J
這裏咱們使用Eclipse - 在項目窗口右擊Properties
以後選擇 JAVA Build Path->中的Libraries ,而後點擊右邊的 Add External JARS 將Connector/J 中的JAR文件導入
這樣就能夠開始編寫了咱們的JDBC了.
1. 創建與數據庫的鏈接,這裏使用DriverManager
咱們須要用到DBMS的 URL 進行鏈接
在用正確的用戶密碼,服務器等等參數鏈接數據庫URL後,
DriverManager 會返回一個Connection,
咱們編寫一個方法來獲取相關的Connection
//根據本身的數據庫進行修改
public class JDBCTutorials {
String userName = "root"; //用戶名
String password = "password";//用戶密碼
String dbms = "mysql";//數據庫管理系統名稱
String serverName = "localhost";//服務器名稱
String portNumber = "3306";//服務器接口
String Atribute = "serverTimezone=UTC"
+ "&characterEncoding=utf-8"
+ "&useSSL=false";//時區與SLL鏈接方式禁用
String dbName = "crashcourse";//須要訪問的數據庫名稱,能夠爲空,可是得本身用USE語句
//jdbc:mysql://localhost:3306/
//jdbc:derby:testdb;create=true
public Connection getConnection() throws SQLException{
Connection conn = null;
Properties connectionPros = new Properties();//新建一個Propeties容器
connectionPros.put("user", userName);
connectionPros.put("password", password);
if(this.dbms.equals("mysql")) {
conn = DriverManager.getConnection("jdbc:" + this.dbms + "://" + this.serverName +
":" + this.portNumber + "/" + this.dbName + "?" + this.Atribute,connectionPros);//獲取鏈接
//conn.setCatalog(this.dbName);
} else if (this.dbms.equals("derby")) {
conn = DriverManager.getConnection("jdbc:" + this.dbms + ":"+ this.dbName + ":"
+ ";create=true",connectionPros);
}
System.out.println("Connection DBMS Successfully");
return conn;
}
}
更改相關的參數後,若是出現
"Connection DBMS Successfully"
就說明鏈接數據庫管理系統成功了.返回的Connection就要用到了,
接下來咱們須要將SQL語句運用起來.
2. 建立Statement , 和執行Query, ResultSet使用(建表 查表)
接下來咱們須要使用的表格以下:
創建這個表格的SQL語句:
//---------------------------------------創建表格-----------------------------------------
CREATE TABLE customers
(
cust_id int NOT NULL AUTO_INCREMENT,
cust_name char(50) NOT NULL ,
cust_address char(50) NULL ,
cust_city char(50) NULL ,
cust_state char(5) NULL ,
cust_zip char(10) NULL ,
cust_country char(50) NULL ,
cust_contact char(50) NULL ,
cust_email char(255) NULL ,
PRIMARY KEY (cust_id)
) ENGINE=InnoDB;
//---------------------------------------填充數據-----------------------------------------
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');
INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');
那麼咱們怎麼使用上面的SQL語句?
首先,咱們要知道以前編寫的 getConnection 方法返回了一個connetion
咱們如今要再執行SQL語句的方法中使用它, SQL語句也須要先儲存到一個String中
public void createTable(Connection con) throws SQLException{ String createSQL = "CREATE TABLE customers\r\n" + //存儲SQL語句
"(\r\n" +
" cust_id int NOT NULL AUTO_INCREMENT,\r\n" +
" cust_name char(50) NOT NULL ,\r\n" +
" cust_address char(50) NULL ,\r\n" +
" cust_city char(50) NULL ,\r\n" +
" cust_state char(5) NULL ,\r\n" +
" cust_zip char(10) NULL ,\r\n" +
" cust_country char(50) NULL ,\r\n" +
" cust_contact char(50) NULL ,\r\n" +
" cust_email char(255) NULL ,\r\n" +
" PRIMARY KEY (cust_id)\r\n" +
") ENGINE=InnoDB;"; try(Statement statement = con.createStatement()){//用connection 建立一個statement
statement.executeUpdate(createSQL);//編譯SQL語句
}catch (Exception e) { System.out.println(e); } }
這樣,建表的SQL語句就完成了.
爲何要把statement的創建寫到try中?
由於JAVA7 提供了自動關閉資源的機制
executeUpdate是什麼?
與之對於的是execute,executeQuery
咱們創建了表,可是表是空的,咱們應該怎麼樣使用SQL的插入語句?
原理相似
public void populateTable(Connection con) throws SQLException{
try(Statement statement = con.createStatement()){
statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');");
statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" +
"VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');");
statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');");
statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');");
statement.execute("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" +
"VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');");//這裏須要使用excute,由於返回多個ResultSet
}catch (Exception e) {
System.out.println(e);
}
}
接着,寫一個查詢表的方法
public void viewTable(Connection con,String dbName) throws SQLException{//查詢表的功能 String query = "SELECT * FROM customers;";//SQL語句 try(Statement statement = con.createStatement()){//建立Statement ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句,用ResultSet存儲查詢結果 while(resultSet.next()) {//換一行 String custID = resultSet.getString("cust_id");//獲取該行列爲"cust_id"的的數據 String custName = resultSet.getString("cust_name"); String custAddress = resultSet.getString("cust_address"); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } }
注意:
executeQuery 是隻能執行一條SQL 語句的,要執行多條須要用到批處理
3.使用
public static void main(String[] args) {
JDBCTutorials jdbcTutorials = new JDBCTutorials();
try (Connection connection = jdbcTutorials.getConnection()){
jdbcTutorials.createTable(connection);
jdbcTutorials.populateTable(connection);
jdbcTutorials.viewTable(connection,"crashcourse");
}catch (SQLException e) {
System.out.println(e);
}
}
執行結果:
4.關閉步驟
通常步驟是:
} finally {
if (stmt != null) { stmt.close(); }
}
不事後來JAVA 7出那個新特性,能夠用try來自動關閉了
try (Statement stmt = con.createStatement()) {
// ...
}
============SQL 語句的處理 以及 鏈接數據庫 的入門結束============
3.專題講解
1.ResultSet 講解 推薦閱讀:
http://www.iteye.com/topic/560109
http://www.javashuo.com/article/p-qgfcntgg-e.html
https://www.tutorialspoint.com/jdbc/jdbc-result-sets.htm (英文)
JAVADOC : https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
ResultSet 有不一樣功能和特性,
1.1 三個特性
光標是什麼?
光標就是指向行的標記,告訴他指向了哪裏.
如圖,左邊的紅箭頭指向的,這個就是個光標,他指着第一行 (cust_id = 10001 .....)
(1) ResultSet 有三個不一樣的類型,
默認類型:TYPE_FORWARD_ONLY
.
TYPE_FORWARD_ONLY:
光標只能向前滾動, (只能使用 next() )
效率:高
TYPE_SCROLL_INSENSITIVE:
先後鼓動的方法 next(),previous() ,回到首尾的方法 first(),last() , 到達指定位置的方法 absolute(int n ) // n表明行數,下標從1開始
光標能夠向前向後滾動,對數據庫的更改不敏感,
效率:中等
TYPE_SCROLL_SENSITIVE:
光標能夠先後移動,對數據庫的更改敏感
只對UPDATE操做有效,對INSERT,DELETE無效
(敏感的意思就是你數據庫更改後,ResultSet的數據也會更改,好比數據庫中第一行第一列的
"蘋果"變爲"李子",ResultSet也會跟着變化)
效率:低
(2) 併發性
默認類型:CONCUR_READ_ONLY.
CONCUR_READ_ONLY:
只讀,在ResultSet中的數據沒法更改
CONCUR_UPDATABLE:
在ResultSet中的數據能夠更改
注意:有些JDBC drivers 和 數據 不支持併發.
(3)光標保持性
默認類型取決你的DBMS
HOLD_CURSORS_OVER_COMMIT:
在事務commit 或rollback 後,ResultSet 仍然可用 (推薦在大部分ResultSet 都是 CONCUR_READ_ONLY 的狀況下使用)
CLOSE_CURSORS_AT_COMMIT:
在事務commit 或rollback 後,ResultSet 不可用
注意:不是全部 數據庫支持
(4)檢測當前數據庫時候支持某種特性
boolean supportsResultSetType(int resultSetType); //類型
boolean supportsResultSetConcurrency(int type, int concurrency);//併發性
boolean supportsResultSetHoldability(int holdability);//保持性
public static void cursorHoldabilitySupport(Connection conn)
throws SQLException {
DatabaseMetaData dbMetaData = conn.getMetaData();
System.out.println("Default cursor holdability: " +
dbMetaData.getResultSetHoldability());//檢測是否支持併發性
System.out.println("Supports HOLD_CURSORS_OVER_COMMIT? " +
dbMetaData.supportsResultSetHoldability(
ResultSet.HOLD_CURSORS_OVER_COMMIT));//檢測時候支持併發性的某一種
System.out.println("Supports CLOSE_CURSORS_AT_COMMIT? " +
dbMetaData.supportsResultSetHoldability(
ResultSet.CLOSE_CURSORS_AT_COMMIT));
}
1.2 功能
1.2.1 控制光標的函數介紹:
先後滾動的方法 next(),previous()
回到首尾的方法 first(),last()
到達指定位置的方法 absolute(int n) // n表明行數,下標從1開始
relative(int n) 移動到相對於當前位置
移動到最後一行後面,此時沒有指向任意行 afterLast()
移動到第一行前面,此時沒有指向任意行 beforeFirst()
1.2.2 ResultSet支持用下標進行查詢,查詢更高效
從左到右,下標從1開始,(即1 表明cust_id 列)
如: int custID = resultSet.getInt(1); // 獲取該行第一列的整數
示範代碼:
public void viewTable(Connection con,String dbName) throws SQLException{ String query =
"SELECT * FROM customers;";//查詢 SQL語句
try(Statement statement = con.createStatement()){//建立Statement
ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句
while(resultSet.next()) { int custID = resultSet.getInt(1); // 獲取該行第一列的整數,即cust_id的信息 String custName = resultSet.getString(2); String custAddress = resultSet.getString(3); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } }
1.2.3 用ResultSet 更新行
用ResultSet.updateFloat(int columnInex , Array x) 去更新行,讓行進行改變,
只有在執行Result.updateRow() 以後,改變纔會生效.
public void changeTable(Connection con,String dbName) throws SQLException{ String query =
"SELECT * FROM customers;";//SQL語句
try(Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){//建立Statement
ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句
resultSet.afterLast();//從前日後更新ID,由於他是 PRIMARY KEY不能重複
while(resultSet.previous()) { int custID = resultSet.getInt(1); resultSet.updateInt(1, custID+1);//客服ID + 1
resultSet.updateRow();//更改生效 } }catch (SQLException e) { System.out.println(e); } }
1.2.4 用ResultSet 插入行
注意:有些JDBC driver不支持 這個功能,若是不支持,會拋出一個 SQLFeatureNotSupportedException
異常
先用 ResultSet.moveToInsertRow(); 將光標移動到要插入的地方
以後用 ResultSet.update() 修改要插入的數據
最後用 ResultSet.insertRow(); 完成插入
public void insertTableReSet(Connection con) throws SQLException{ String query =
"SELECT * FROM customers;";//SQL語句
try (Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){ ResultSet resultSet = statement.executeQuery(query); resultSet.moveToInsertRow(); resultSet.updateInt(1, 10006); resultSet.updateString(2, "New Man"); resultSet.updateString(3, "3123 street"); resultSet.insertRow(); }catch (Exception e) { System.out.println(e); } }
2.Statement
2.1 Statement 方法
Statement和ResultSet是怎麼工做的?
查詢到的的數據先存到數據庫的緩衝中,ResultSet就是對緩衝數據的應用.
setFetchsize 設置每次獲取的數據數(rs.next),當數據數量多,處理時間長,就須要用到
setMaxRows 限制返回的數據集數量,相似SQL 中的LIMIT
getGeneratedKeys() 獲取自動生成的主鍵值.
executeQuery 只執行查 (select語句)
executeUpdate 執行 增刪改 (insert或者update/delete(DML)語句,或者 什麼也不返回的DDL語句)
execute 執行 增刪改查
2.2 PreparedStatement
PreparedStatement 是一個預編譯SQL語句,能夠用setter傳入參數
也就是能夠用有參數的SQL語句了,參數代替用 ? 從左往右排序, 下標爲1開始.
動態參數化用來查詢的 演示代碼:
public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{ String query =
"SELECT * FROM customers WHERE cust_id = ?;";// ? 能夠用一個參數代替
try(PreparedStatement statement = con.prepareStatement(query)){//建立Statement
ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句
int i = 0; while(resultSet.next()) { statement.setInt(1, 10001 + i++);//用 10001 + i 替代 第一個 ?
int custID = resultSet.getInt(1); String custName = resultSet.getString(2); String custAddress = resultSet.getString(3); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } }
能夠用一個循環去設置參數
for(Map.Entry<Integer, String> e: customerCondition.entrySet()) { statement.setInt(1, e.getKey()); statement.setString(2, e.getValue()); //寫執行語句 }
演示代碼:
public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{ String query =
"SELECT * FROM customers WHERE cust_id = ? AND cust_name = ?;";//? 能夠用一個參數代替
HashMap<Integer, String> customerCondition = new HashMap<>(); customerCondition.put(10001, "Coyote Inc."); customerCondition.put(10002, "Mouse House"); customerCondition.put(10003, "Wascals"); customerCondition.put(10004, "Yosemite Place"); customerCondition.put(10005, "New Man"); try(PreparedStatement statement = con.prepareStatement(query)){//建立Statement
ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句
int i = 0; for(Map.Entry<Integer, String> e: customerCondition.entrySet()) { statement.setInt(1, e.getKey()); statement.setString(2, e.getValue()); resultSet.next(); int custID = resultSet.getInt(1); String custName = resultSet.getString(2); String custAddress = resultSet.getString(3); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } }
優勢:
性能比Statement 好,
還能夠防止臭名昭著的 SQL注入 攻擊, 簡單原理
應該儘可能使用PreparedStatement.
缺點:
沒法使用 IN 語句,
解放方案
1.多個單條SQL語句拼成與有 IN 語句同樣的查詢 -- 效率低
2.使用存儲過程, (由於存儲過程是數據庫專有,
推薦在只使用一種數據庫 和 不打算換數據庫服務器 的狀況下使用)
3.動態生成PreparedStatement查詢 (可是沒法 使用 PreparedStatement caching)
4.使用NULL在PreparedStatement查詢.(推薦)
第四種方法的演示代碼:
public void viewTablePreaparedStatementNull(Connection con) { final String QUERY = "SELECT * FROM customers WHERE cust_id IN (?,?,?,?,?,?,?,?,?,?);"; final int PARAM_SIZE = 10; int[] ids = {10001,10002,10003,10004,10005}; if(ids.length > PARAM_SIZE) { System.out.println("MAXIMUM INPUT SIZE " + PARAM_SIZE); return; } int i = 1; try(PreparedStatement preparedStatement = con.prepareStatement(QUERY)){ for(; i<= ids.length;i++) {//填充參數 preparedStatement.setInt(i, ids[i-1]); } for(; i<=PARAM_SIZE;i++) {//設置未填充的參數爲空 preparedStatement.setNull(i, java.sql.Types.INTEGER); } try(ResultSet re = preparedStatement.executeQuery()){ while(re.next()) { System.out.println(re.getInt(1) + " "+ re.getString(2)); } }catch (SQLException e) { e.printStackTrace(); } }catch (SQLException e) { e.printStackTrace(); } }
2.3 CallableStatement
調用儲存過程
SQL語句
DROP procedure IF exists SHOW_CUSTOMERS; DELIMITER // CREATE PROCEDURE SHOW_CUSTOMERS( IN in_cust_id INT, OUT out_cust_name VARCHAR(40) ) BEGIN SELECT cust_name FROM customers WHERE cust_id = in_cust_id INTO out_cust_name; END// DELIMITER ; CALL SHOW_CUSTOMERS(10006,@custID); SELECT @custID;
演示代碼:
建立存儲過程
public void createStoredProcedure(Connection con) { String dropProcedure = "DROP procedure IF exists SHOW_CUSTOMERS;"; String createProcedure = "CREATE PROCEDURE SHOW_CUSTOMERS(\r\n" + " IN in_cust_id INT,\r\n" + " OUT out_cust_name VARCHAR(40)\r\n" + ")\r\n" + "BEGIN\r\n" + " SELECT cust_name FROM customers\r\n" + " WHERE cust_id = in_cust_id INTO out_cust_name;\r\n" + "END;"; try(CallableStatement cs = con.prepareCall(createProcedure);PreparedStatement ps = con.prepareStatement(dropProcedure)){ ps.executeUpdate(); cs.executeUpdate(); }catch(SQLException e){ e.printStackTrace(); } }
使用存儲過程
public void useStoredProcedure(Connection con) { try(CallableStatement cs = con.prepareCall("{CALL SHOW_CUSTOMERS(?,?)}")){ cs.setInt(1, 10005); cs.registerOutParameter(2, Types.CHAR); cs.executeQuery(); System.out.println(cs.getString(2)); }catch(SQLException e) { e.printStackTrace(); } }
3.批處理 + 刪除表格
主要用到statement中
addBatch ,executeBatch ,clearBatch 三個方法.
即添加語句,執行語句,清除含有的語句.
接下來咱們須要用 批處理 從新建立 填充表格的方法,
爲了容易說明, 咱們須要刪除掉剛剛的表,而後從新建立,再填充.
刪表的原理相似與建表
public void dropTable(Connection con) throws SQLException{ String query = "DROP TABLE customers"; try(Statement statement = con.createStatement()){//建立Statement
statement.executeUpdate(query);//編譯SQL語句
}catch (SQLException e) { System.out.println(e); } }
刪除表以後,咱們從新建立表(原理相似),而後再使用填充方法
用批處理寫的填充方法:
public void populateTable(Connection con) throws SQLException{ try(Statement statement = con.createStatement()){ con.setAutoCommit(false);//開啓事務
statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" +
"VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" +
"VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" +
"VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');"); int[] successNum = statement.executeBatch();//返回成功數,而且執行批語句
System.out.println("成功插入:" + Arrays.toString(successNum)); con.commit(); }catch (Exception e) { System.out.println(e); }finally{ con.setAutoCommit(true); } }
4.DataSource 與鏈接池,事務
1.1DataSource 與鏈接池
推薦閱讀:http://www.javashuo.com/article/p-cygaddcx-a.html
通常開源的數據鏈接池有兩種:C3P0 與 DBCP 區別與介紹
接下來咱們要用
javax.sql.DataSource;
中 DataSource 來寫一個簡易鏈接池.
首先明確幾個概念.
鏈接池:
鏈接數據庫的操做十分昂貴,
因此咱們想到能夠把已經創建好的鏈接先存起來,
這就用到了鏈接池.
動態代理模式:
使用一個代理類 代理 原有的對象, 在代理類中原有對象的方法調用以前,
都要通過代理類的處理,而後再決定是否回到原有對象.
好比: 咱們的Connection中有一個close() 方法,意思就是關閉鏈接,
那麼咱們須要修改Connecttion.close()的執行方式,這時候就須要
寫一個代理類代理Connection類.
簡易鏈接池的思路:
1.實現DataSource接口,批量建立必定 鏈接(connection) 而且將其加入 容器 中
2.每次使用getConnection(),都從容器中去除一個 鏈接(connection),若是容器中沒有可用容器,提示"數據庫繁忙"
3.每次close的時候,保證用完的 鏈接(connection) 回到容器中.
簡易鏈接池代碼:
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.LinkedList; import java.util.Properties; import java.util.logging.Logger; import javax.management.RuntimeErrorException; import javax.sql.DataSource; public class JDBCPool implements DataSource{ private static LinkedList<Connection> conPool = new LinkedList<Connection>(); static { //InputStream in = JDBCPool.class.getClassLoader().getResourceAsStream("db.properties"); //Properties pro = new Properties(); try { //pro.load(in); //String driver = pro.getProperty("driver"); //String url = pro.getProperty("url"); //String username = pro.getProperty("username"); //String password = pro.getProperty("password"); //int jdbcPoolInitSize = Integer.parseInt(pro.getProperty("jdbcPoolInitSize")); String driver = "mysql"; String url = "jdbc:mysql://localhost:3306/crashcourse?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true"; String username = "root"; String password = "***"; int jdbcPoolInitSize = 10; for(int i=0;i<jdbcPoolInitSize;i++) { Connection connection = DriverManager.getConnection(url,username,password); System.out.println("初始化數據庫 " + (i+1) + "個鏈接"); conPool.add(connection); } }catch (SQLException e) { e.printStackTrace(); } } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { // TODO Auto-generated method stub return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } @Override public Connection getConnection() throws SQLException { // TODO Auto-generated method stub if(conPool.size() > 0) { final Connection conn = conPool.removeFirst(); return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[] {Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(!"close".equals(method.getName())) { return method.invoke(conn, args); } else { conPool.add(conn); System.out.println("關閉鏈接,實際還給了鏈接池"); System.out.println("池中鏈接數爲 " + conPool.size()); return null; } } }); }else { throw new RuntimeErrorException(null, "數據庫繁忙"); } } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public PrintWriter getLogWriter() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } @Override public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } }
另外一個調用類代碼:
import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.Properties; import java.sql.CallableStatement; import java.sql.Connection; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import javax.sql.DataSource; public class JDBCTutorials { JDBCPool jdbcPool = new JDBCPool(); String userName = "root"; //用戶名 String password = "***";//用戶密碼 String dbms = "mysql";//數據庫管理系統名稱 String serverName = "localhost";//服務器名稱 String portNumber = "3306";//服務器接口 String Atribute = "serverTimezone=UTC" + "&characterEncoding=utf-8" + "&useSSL=false" + "&allowPublicKeyRetrieval=true";//時區與SLL鏈接方式禁用 String dbName = "crashcourse";//數據庫名稱 //jdbc:mysql://localhost:3306/ //jdbc:derby:testdb;create=true public Connection getConnection() throws SQLException{ Connection conn = jdbcPool.getConnection(); // Connection conn = null; // Properties connectionPros = new Properties(); // connectionPros.put("user", userName); // connectionPros.put("password", password); // if(this.dbms.equals("mysql")) { // conn = DriverManager.getConnection("jdbc:" + this.dbms + "://" + this.serverName + // ":" + this.portNumber + "/" + this.dbName + "?" + this.Atribute,connectionPros); // //conn.setCatalog(this.dbName); // } else if (this.dbms.equals("derby")) { // conn = DriverManager.getConnection("jdbc:" + this.dbms + ":"+ this.dbName + ":" // + ";create=true",connectionPros); // } // System.out.println("Connection DBMS Successfully"); return conn; } public void viewTable(Connection con,String dbName) throws SQLException{ String query = "SELECT * FROM customers;";//SQL語句 try(Statement statement = con.createStatement()){//建立Statement ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句 while(resultSet.next()) { int custID = resultSet.getInt(1); String custName = resultSet.getString(2); String custAddress = resultSet.getString(3); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } } public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{ String query = "SELECT * FROM customers WHERE cust_id = ? AND cust_name = ?;";//? 能夠用一個參數代替 HashMap<Integer, String> customerCondition = new HashMap<>(); customerCondition.put(10001, "Coyote Inc."); customerCondition.put(10002, "Mouse House"); customerCondition.put(10003, "Wascals"); customerCondition.put(10004, "Yosemite Place"); customerCondition.put(10005, "New Man"); try(PreparedStatement statement = con.prepareStatement(query)){//建立Statement ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句 int i = 0; for(Map.Entry<Integer, String> e: customerCondition.entrySet()) { statement.setInt(1, e.getKey()); statement.setString(2, e.getValue()); resultSet.next(); int custID = resultSet.getInt(1); String custName = resultSet.getString(2); String custAddress = resultSet.getString(3); System.out.println(custID + ", " + custName + ", " + custAddress); } }catch (SQLException e) { System.out.println(e); } } public void viewTablePreaparedStatementNull(Connection con) { final String QUERY = "SELECT * FROM customers WHERE cust_id IN (?,?,?,?,?,?,?,?,?,?);"; final int PARAM_SIZE = 10; int[] ids = {10001,10002,10003,10004,10005}; if(ids.length > PARAM_SIZE) { System.out.println("MAXIMUM INPUT SIZE " + PARAM_SIZE); return; } int i = 1; try(PreparedStatement preparedStatement = con.prepareStatement(QUERY)){ for(; i<= ids.length;i++) { preparedStatement.setInt(i, ids[i-1]); } for(; i<=PARAM_SIZE;i++) { preparedStatement.setNull(i, java.sql.Types.INTEGER); } try(ResultSet re = preparedStatement.executeQuery()){ while(re.next()) { System.out.println(re.getInt(1) + " "+ re.getString(2)); } }catch (SQLException e) { e.printStackTrace(); } }catch (SQLException e) { e.printStackTrace(); } } public void changeTable(Connection con,String dbName) throws SQLException{ String query = "SELECT * FROM customers;";//SQL語句 try(Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){//建立Statement ResultSet resultSet = statement.executeQuery(query);//編譯SQL語句 resultSet.afterLast();//從前日後更新ID,由於他是 PRIMARY KEY不能重複 while(resultSet.previous()) { int custID = resultSet.getInt(1); resultSet.updateInt(1, custID+1);//客服ID + 1 resultSet.updateRow(); } }catch (SQLException e) { System.out.println(e); } } public void dropTable(Connection con) throws SQLException{ final String QUERY = "DROP TABLE customers"; try(Statement statement = con.createStatement()){//建立Statement statement.executeUpdate(QUERY);//編譯SQL語句 }catch (SQLException e) { System.out.println(e); } } public void createTable(Connection con) throws SQLException{ String createSQL = "CREATE TABLE customers\r\n" + "(\r\n" + " cust_id int NOT NULL AUTO_INCREMENT,\r\n" + " cust_name char(50) NOT NULL ,\r\n" + " cust_address char(50) NULL ,\r\n" + " cust_city char(50) NULL ,\r\n" + " cust_state char(5) NULL ,\r\n" + " cust_zip char(10) NULL ,\r\n" + " cust_country char(50) NULL ,\r\n" + " cust_contact char(50) NULL ,\r\n" + " cust_email char(255) NULL ,\r\n" + " PRIMARY KEY (cust_id)\r\n" + ") ENGINE=InnoDB;"; try(Statement statement = con.createStatement()){ statement.executeUpdate(createSQL); }catch (Exception e) { System.out.println(e); } } public void populateTableBatch(Connection con) throws SQLException{ try(Statement statement = con.createStatement()){ con.setAutoCommit(false);//關閉事務自動commit 和 rollback statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" + "VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" + "VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');"); int[] successNum = statement.executeBatch();//返回成功數 System.out.println("成功插入:" + Arrays.toString(successNum)); con.commit(); }catch (Exception e) { System.out.println(e); }finally{ con.setAutoCommit(true); } } public void insertTableReSet(Connection con) throws SQLException{ String query = "SELECT * FROM customers;";//SQL語句 try (Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){ ResultSet resultSet = statement.executeQuery(query); resultSet.moveToInsertRow(); resultSet.updateInt(1, 10006); resultSet.updateString(2, "New Man"); resultSet.updateString(3, "3123 street"); resultSet.insertRow(); }catch (Exception e) { System.out.println(e); } } public void createStoredProcedure(Connection con) { String dropProcedure = "DROP procedure IF exists SHOW_CUSTOMERS;"; String createProcedure = "CREATE PROCEDURE SHOW_CUSTOMERS(\r\n" + " IN in_cust_id INT,\r\n" + " OUT out_cust_name VARCHAR(40)\r\n" + ")\r\n" + "BEGIN\r\n" + " SELECT cust_name FROM customers\r\n" + " WHERE cust_id = in_cust_id INTO out_cust_name;\r\n" + "END;"; try(CallableStatement cs = con.prepareCall(createProcedure);PreparedStatement ps = con.prepareStatement(dropProcedure)){ ps.executeUpdate(); cs.executeUpdate(); }catch(SQLException e){ e.printStackTrace(); } } public void useStoredProcedure(Connection con) { try(CallableStatement cs = con.prepareCall("{CALL SHOW_CUSTOMERS(?,?)}")){ cs.setInt(1, 10005); cs.registerOutParameter(2, Types.CHAR); cs.executeQuery(); System.out.println(cs.getString(2)); }catch(SQLException e) { e.printStackTrace(); } } public static void main(String[] args) { JDBCTutorials jdbcTutorials = new JDBCTutorials(); try (Connection connection = jdbcTutorials.getConnection()){ jdbcTutorials.dropTable(connection); jdbcTutorials.createTable(connection); jdbcTutorials.populateTableBatch(connection); jdbcTutorials.insertTableReSet(connection); jdbcTutorials.viewTablePreaparedStatementNull(connection); jdbcTutorials.changeTable(connection,"crashcourse"); System.out.println(); jdbcTutorials.viewTable(connection,"crashcourse"); System.out.println(); jdbcTutorials.createStoredProcedure(connection); jdbcTutorials.useStoredProcedure(connection); }catch (SQLException e) { System.out.println(e); } } }
DBCP使用(JDNI):
推薦閱讀:http://www.javashuo.com/article/p-guhslqsa-e.html
去官方下三個包 http://commons.apache.org/proper/
基礎的BasicDataSource 就是咱們的第三類DataSource(鏈接池,Connection,事務)
public Connection getConnection() { Connection con = null; BasicDataSource ds = new BasicDataSource(); ds.setUrl("jdbc:mysql://localhost:3306/crashcourse?serverTimezone=GMT&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true"); ds.setDriverClassName("com.mysql.cj.jdbc.Driver"); ds.setUsername("root"); ds.setPassword("***"); ds.setMaxTotal(30); try{ con = ds.getConnection( ); }catch(SQLException e) { e.printStackTrace(); } return con; }
咱們能夠用.properties 來保存BasicDataSource的配置
########DBCP配置文件########## #驅動名 driverClassName=com.mysql.jdbc.Driver #url url=jdbc:mysql://127.0.0.1:3306/mydb #用戶名 username=sa #密碼 password=123456 #初試鏈接數 initialSize=30 #最大活躍數 maxTotal=30 #最大idle數 maxIdle=10 #最小idle數 minIdle=5 #最長等待時間(毫秒) maxWaitMillis=1000 #程序中的鏈接不使用後是否被鏈接池回收(該版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow) #removeAbandoned=true removeAbandonedOnMaintenance=true removeAbandonedOnBorrow=true #鏈接在所指定的秒數內未使用纔會被刪除(秒)(爲配合測試程序才配置爲1秒) removeAbandonedTimeout=1
而後寫一個類來用它
public class JDBCPool { private static Properties properties = new Properties(); private static DataSource dataSource; static { try (FileInputStream is = new FileInputStream("config/dbcp.properties")){ dataSource = BasicDataSourceFactory.createDataSource(properties); properties.load(is); } catch (IOException e){ e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() { Connection connection = null; try { connection = dataSource.getConnection(); }catch(SQLException e){ e.printStackTrace(); } return connection; } }
1.2 事務
轉帳是一種典型的使用事務的案例
轉出帳戶和轉入帳戶必須同時執行成功才能算做是一次轉帳,若是一方沒有執行成功,那麼另外一方也要不執行
由於JDBC中commit是默認開啓,
要使用事務就得將其關閉,而且事務內的鏈接(Connection)只有一個
Connection.setAutoCommit(false);
在語句的最後使用 Connection.commit(); 提交
或者在中途使用Connection.rollback();回滾
public void populateTableBatch(Connection con) throws SQLException{ try(Statement statement = con.createStatement()){ con.setAutoCommit(false);//開啓事務 statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" + "VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)\r\n" + "VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');"); statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)\r\n" + "VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');"); int[] successNum = statement.executeBatch();//返回成功數 System.out.println("成功插入:" + Arrays.toString(successNum)); con.commit(); }catch (Exception e) { System.out.println(e); con.rollback(); }finally{ con.setAutoCommit(true); } }
=============== 專題介紹結束 ===============
4.結尾
1. ORM (Object relation mapping) 對象關係映射
ORM 是一種思想,將數據庫中的數據變成對象,對象變成數據庫中的數據。
由於咱們編程語言是面對對象的,一切都是對象,而關係數據庫是有數學理論發展起來的,
這二者直接有必定區別,ORM就是爲了解決這個問題而存在的。
https://blog.csdn.net/ma15732625261/article/details/74332441
ORM 工具介紹:ADO.NET等
2. DAO 封裝本身的JDBC
DAO: DAO 就是一個模型,它將數據庫與業務邏輯之間,將訪問數據庫的代碼封裝成一個類。(增刪改,不包含業務信息)
須要的包:
http://commons.apache.org/proper/
仍是用上面的表
寫一個Customers 類
public class Customers { int custID; String custName; String custAddress; String custCity; String custState; String custZip; @Override public String toString() { return "Customers [custID=" + custID + ", custName=" + custName + ", custAddress=" + custAddress + ", custCity=" + custCity + ", custState=" + custState + ", custZip=" + custZip + ", custCountry=" + custCountry + ", custContact=" + custContact + ", custEmail=" + custEmail + "]"; } String custCountry; String custContact; String custEmail; public int getCustID() { return custID; } public void setCustID(int custID) { this.custID = custID; } public String getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCustAddress() { return custAddress; } public void setCustAddress(String custAddress) { this.custAddress = custAddress; } public String getCustCity() { return custCity; } public void setCustCity(String custCity) { this.custCity = custCity; } public String getCustState() { return custState; } public void setCustState(String custState) { this.custState = custState; } public String getCustZip() { return custZip; } public void setCustZip(String custZip) { this.custZip = custZip; } public String getCustCountry() { return custCountry; } public void setCustCountry(String custCountry) { this.custCountry = custCountry; } public String getCustContact() { return custContact; } public void setCustContact(String custContact) { this.custContact = custContact; } public String getCustEmail() { return custEmail; } public void setCustEmail(String custEmail) { this.custEmail = custEmail; } }
DAO類:
import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; public class Dao { public void updata(String sql,Object... args) { try(Connection con = JDBCTutorials.getConnection(); PreparedStatement pre = con.prepareStatement(sql)){ for(int i=0;i<args.length;i++) { pre.setObject(i+1, args); } pre.executeUpdate(); }catch (SQLException e) { e.printStackTrace(); } } @SuppressWarnings("deprecation") /** * 返回一條查詢記錄 * @param rs * @return * @throws SQLException */ public <T> T get(Class<T> dataClass,String sql,Object... args){ List<T> list = new LinkedList<>(); list = getForList(dataClass,sql,args); if(list.size() > 0) { return list.get(0); }else { return null; } } /** * 返回多條查詢記錄 * @param rs * @return * @throws SQLException */ @SuppressWarnings("deprecation") public <T> List<T> getForList(Class<T> dataClass,String sql,Object... args){ //1.獲得結果集 List<T> list = new LinkedList<T>(); try(Connection con = JDBCTutorials.getConnection(); PreparedStatement pre = con.prepareStatement(sql)){ for(int i=0;i<args.length;i++) { pre.setObject(i+1, args[i]); } try(ResultSet rs = pre.executeQuery()){ //2.處理結果集, 獲得Map的List,其中一個Map對象對應着一條記錄 //Map 的 Key 是 ReusltSet別名,value爲列的值。 List<Map<String, Object>> mapList = handlerResultSetToMap(rs); //3.處理Map 中的List 變爲 dataClass 的List //Map的key 爲 dataClass的屬性名,value 爲dataClass的屬性值 list = transferMapListToLinkedList(dataClass, mapList); }catch (SQLException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }catch (SQLException e) { e.printStackTrace(); } return list; } private <T> List<T> transferMapListToLinkedList(Class<T> dataClass, List<Map<String, Object>> mapList) throws InstantiationException, IllegalAccessException, InvocationTargetException { T entity = null; LinkedList<T> list = new LinkedList<T>(); if(mapList.size()>0) { for(Map<String, Object> mt:mapList) { entity = dataClass.newInstance(); for(Map.Entry<String, Object> m:mt.entrySet()) { String proName = m.getKey(); Object value = m.getValue(); BeanUtils.setProperty(entity, proName, value);//填充entity的屬性 } list.add(entity); } } return list; } private List<Map<String, Object>> handlerResultSetToMap(ResultSet rs) throws SQLException { List<Map<String,Object>> mapList = new LinkedList<Map<String,Object>>(); List<String> columnLabel = getColumnLabels(rs); while(rs.next()) { Map<String,Object> mapz = new HashMap<String,Object>(); for(String colName:columnLabel) { Object colObject = rs.getObject(colName); mapz.put(colName, colObject); } mapList.add(mapz); } return mapList; } public List<String> getColumnLabels(ResultSet rs) throws SQLException{ List<String> list = new LinkedList<String>(); ResultSetMetaData resultSetMetaData = rs.getMetaData(); for(int i=0;i<resultSetMetaData.getColumnCount();i++) { list.add(resultSetMetaData.getColumnLabel(i+1)); } return list; } /** * 返回某條記錄的字段 * @param sql * @param args * @return */ public <E> E getForValue(String sql,Object... args) { try(Connection con = JDBCTutorials.getConnection(); PreparedStatement pre = con.prepareStatement(sql)){ for(int i=0;i<args.length;i++) { pre.setObject(i+1, args[i]); } try(ResultSet rs = pre.executeQuery()){ if(rs.next()) { return (E)rs.getObject(1); } }catch (SQLException e) { e.printStackTrace(); } }catch (SQLException e) { e.printStackTrace(); } return null; } }
DaoTest類
class DaoTest { Dao dao = new Dao(); @Test void testUpdata() { String sql = "SELECT cust_id custID,cust_name custName FROM customers WHERE cust_id = ?;"; Customers customers = dao.get(Customers.class, sql,10003); System.out.println("---"); System.out.println(customers); } @Test void testGet() { String sql = "SELECT cust_id custID,cust_name custName FROM customers WHERE cust_id = ? OR cust_id = ?;"; List<Customers> customers = dao.getForList(Customers.class, sql,10003,10004); for(Customers l:customers) { System.out.println(l); } } @Test void testGetValue() { String sql = "Select MAX(cust_id) FROM customers"; int maxCustID = dao.getForValue(sql); System.out.println(maxCustID); } }
日期:2018-10-18 基礎教程寫好,後續拓展待補:
2018-10-19 14:20:15 更新拓展.
2018-10-20 21:55:52 第二大部分即將完成,編寫鏈接池概念與原理中
2018-10-22 修正
2018-10-23 13:57:55 完結撒花