要面試,因此把以前的筆記整理一遍,嘻嘻,加油java
JDBC編程mysql
JDBC(Java Database Connectiovity,Java數據庫鏈接)是一種執行SQL語句的JavaAPI,程序能夠經過JDBC API鏈接數據庫,並使用SQL結構化查詢語言完成對數據庫的操做,程序員使用JDBC編程時只須要掌握標準的JDBC API 便可,當須要在不一樣的數據庫之間切換時,只須要更換不一樣的數據庫驅動類,是面向接口編程的典例應用。ios
JDBC訪問數據庫時主要完成三個操做:程序員
JDBC驅動: 數據庫驅動程序是JDBC程序和數據庫之間的轉換層,數據庫驅動程序負責將JDBC調用映射成特定的數據庫調用,有4種類型:JDBC-ODBC橋(最先),本地API驅動,網絡協議驅動,本地協議驅動(建議使用,純java編寫)。面試
JDBC API:提供一組用於與數據庫進行通訊的接口和類,都定義在java.sql包下。sql
Java.sql包經常使用接口和類數據庫
使用JDBC API中的類或者接口訪問數據庫時,容易引起SQLException異常,屬於檢查性異常。須要放在try……catch語句裏,對於DriverManager來說,要用到ClassNotFoundException異常。編程
DriverManager類:是數據庫驅動管理類,用於管理一組JDBC驅動程序的基本服務,應用程序和數據庫之間能夠經過DriverManager創建鏈接,網絡
DriverManager經常使用靜態方法併發
Connection接口:用於鏈接數據,每一個Connection表明一個數據庫鏈接會話,一個應用程序能夠與單個或者多個數據庫鏈接,經過DriverManager類的getConnection()方法能夠返回同一個Connection對象,該對象提供建立SQL的語法,完成基本SQL操做
Connection的經常使用方法
Statement接口:通常用於執行SQL語句,在JDBC中要執行SQL查詢語句的方式有
三種方式。Statement和PreparedStatement和CallableStatement三個接口具備依次繼承關係。
Statement接口經常使用方法
ResultSet接口:用於封裝結果集對象,該對象包含訪問查詢結果的方法,使用Statement中的executeQuery()方法能夠返回一個ResultSet結果集對象(f封裝了全部查詢條件的記錄),ResultSet具備指向當前數據行的遊標,並提供了許多方法來操做結果集中的遊標,提供getXXX()方法對結果集進行訪問。調用next()方法遊標會向下移動,
ResultSet接口經常使用方法
數據庫環境搭建:
數據庫訪問:使用JDBC訪問數據庫步驟:
Connection conn = DriverManager.getConnection(String url,String user,String pass);
mysql:DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root","mysql");
oracle:DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","sys as sysdba","oracle");
Statement接口:
execute()方法能夠執行任何SQL語句,返回值爲布爾型表示是否返回了ResultSet對象,true時使用Statement的getResultSet()方法來獲取execute()方法執行SQL語句返回的ResultSet對象;false時使用getUpdateCount()方法獲取受影響得行數。
executeUpdate()和executeLargeUpdate():用於執行DML和DDL語句,返回對應的行數和0;當DML語句影響的記錄超過Integer.MAX_VALUE時,使用executeLargeUpdate(),類型爲long;
PreparedStatement接口:
PreparedStatement對象包含的SQL語句進行預編譯,須要屢次執行相同的SQL語句時,編譯好的語句比Statement對象快。能夠執行動態的SQL語句,即在SQL 語句中提供參數,動態SQL語句中用?做爲動態參數的佔位符。用setXXX()的方法經過佔位符的索引完成對參數的賦值。
例:String insterSql = "INSERT INTO LIRUILONG.my_tests VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(insterSql);
ps.setInt(1,4);
ps.setString(2, "李瑞龍");
CallableStatement接口:
JDBC提供CallableStatement接口,用於執行數據庫的儲存過程,該接口能夠處理通常的SQL 語句,也能夠處理以三種帶參數(IN ,OUT,IN OUT)的SQL儲存過程,使用Connection類的prepareCall(String sql)方法能夠建立一個CallableStatement對象,方法的參數能夠是一個調用存儲過程的字符串,cast = conn.prepareCall("{call LIRUILONG.addSub(?,?)");對CallableStatement的SQL語句執行通常用execute().
調用存儲過程的SQL:「{call 存儲過程名[(參數佔位符?)]}」、、有返回值的:「{參數佔位符?=call 存儲過程名[(參數佔位符?)]}」
CallableStatement接口經過setXXX()方法對IN參數進行賦值,
經過registerOutParameter(1, sql.Types.)方法對OUT參數進行類型註冊,第二個參數一般使用java.sql.Types靜態常量指定。
檢索結果的獲取經過getXXX()方法獲取OUT和IN OUT參數的值,
對於IN OUT 參數的值來說須要先使用setXXX()方法對參數進行設置,而後使用registerOutParameter()進行類型註冊,最後使用getXXX()方法來獲取檢索結果
數據庫訪問優化:
即編寫一個數據庫訪問工具類DBUtil,用於提供訪問數據庫時所用到的鏈接,查詢等
編寫屬性文件:存放鏈接數據庫的參數信息,在項目的更目錄下建立一個config子目錄。並添加一個屬性文件oracle.properties,該文件以鍵-值對的形式保存鏈接Oracle的配置信息。在讀取配置文件的配置信息時,須要編寫一個Config配置類,在給類中經過java.util.Properrties類的get()方法來獲取指定的「鍵」所對應的值。
編寫DBUtil工具類。將SQL語句與參數包裝傳遞
使用DBUtil工具類。
集元數據
集元數據(Meta Data)是有關數據庫和表結構的信息,JDBC提供了獲取這些信息的DatabaseMetaData和ResultSetMetaData接口。
DatabaseMetaData接口:DatabaseMetaData接口主要用於獲取數據庫相關信息,如數據庫的全部表的列表,系統函數,關鍵字,數據庫產品名以及驅動類型。DatabaseMetaData對象經過getMetaData()方法進行獲取。DatabaseMetaData接口提供大量獲取信息的方法,這些方法可分爲兩大類:
DatabaseMetaData
ResultSetMetaData接口:用於獲取結果集的結構信息,經過ResultSet的getMetaData()方法來獲取對應的ResultSetMetaData對象
ResultSetMetaData的經常使用方法
事務處理:
事務是保證底層數據完整的重要手段由一步或幾步數據庫操做序列注組成的邏輯執行單元。事務具備ACID四個特性:
事務處理包括事務提交,終止和回滾,事務提交分顯式提交(commit)和自動提交,事務終止指未能成功完成事務,執行中斷,事務回滾有顯式回滾(rollback)和自動回滾(系統錯誤或強行退出)
JDBC對事務操做由Connection提供:
開啓事務,執行任意多條DML語句,執行成功提交事務,失敗回滾事務,Connection在默認狀況下會自動提交,及事務是關閉的,一條SQL語句執行後,系統調用commit()方法提交數據庫,沒法回滾,使用Connection的setAutoCommit()方法能夠開啓關閉自動提交模式(事務),該方法爲布爾型,參數false爲關閉自動提交,反之打開自動提交。
當程序遇到未處理的SQLException異常,都會自動回滾,當捕獲該異常時,則須要在處理塊中顯示回滾。
保存點操做:
批量更新:
---------------------
JDBC工具類
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/project jdbc.user=root jdbc.password=123456 jdbc.datasource.size=10
package com.lirong.sparkproject.constant; public interface Constants { /** * 數據庫相關常量 */ String JDBC_DRIVER = "jdbc.driver"; String JDBC_URL = "jdbc.url"; String JDBC_USER = "jdbc.user"; String JDBC_PASSWORD = "jdbc.password"; String JDBC_DATASOURCE_SIZE="jdbc.datasource.size"; }
import java.io.InputStream; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import com.lirong.sparkproject.constant.Constants; public abstract class JDBCHelper { //配置對象 private static Properties prop=new Properties(); /* * jdbc變量 */ static String driver=null; static String url=null; static String user=null; static String password=null; //thread封裝Connection對象 static ThreadLocal<Connection> thread=new ThreadLocal<Connection>(); //惟一空構造器私有化,不容許外部建立對象 private JDBCHelper() {} /** * 靜態代碼塊爲jdbc變量賦值 * 由於靜態代碼塊最早執行,因此調用getConnection()方法時, * 該方法內部的jdbc變量就完成了賦值操做 */ static { try { //動態獲取配置文件的路徑 InputStream in=JDBCHelper.class.getClassLoader().getResourceAsStream("my.properties"); prop.load(in);//加載鍵值對信息 /* * Constants常量接口中保存了不少常量,這些常量的值就是配置文件k-v數據的鍵 * */ driver=prop.getProperty(Constants.JDBC_DRIVER); url=prop.getProperty(Constants.JDBC_URL); user=prop.getProperty(Constants.JDBC_USER); password=prop.getProperty(Constants.JDBC_PASSWORD); /* * 加載驅動,靜態代碼塊只執行一次,驅動只加載一次(加載驅動很耗性能的) */ Class.forName(driver);//加載驅動 } catch (Exception e) { e.printStackTrace(); } } /** * 經過本方法客獲取一個MySQL數據庫的Connection對象 * * @return Connection對象 */ public static Connection getConnection() { Connection con = thread.get(); if(con==null) { try { con = DriverManager.getConnection(url, user, password); thread.set(con); } catch (SQLException e) { e.printStackTrace(); } } return con;//返回jdbc鏈接 } /** * 本方法中調用Date類型變量的setter方法時使用的是java.sql.Date, * 因此實體類在聲明Date類型變量時必定聲明成java.sql.Date * 至少Date類型變量對應的setter方法的形參必須是java.sql.Date,不然報錯 * * 查詢完畢後,使用者經過JDBCHelper.getConnection()獲取鏈接對象,並關閉它 * 外部獲取的鏈接對象與本方法使用的鏈接對象,在同一線程類,是同一個對象 * * @param sql 要執行的查詢語句 * @param t 實體類對象 * @param objs SQL語句中的參數 * @return 裝有實體類對象的list集合 */ public static <T> List<T> executeQuery(String sql,T t,Object...objs){ //聲明jdbc變量 List<T> list=new ArrayList<>(); Connection conn = null; PreparedStatement ps =null; ResultSet rs =null; try { conn = JDBCHelper.getConnection(); ps = conn.prepareStatement(sql); //給佔位符賦值 if(objs!=null) { for(int i=0;i<objs.length;i++) { ps.setObject((i+1), objs[i]); } } //執行sql語句 rs = ps.executeQuery(); //獲取結果集中字段的全部信息 ResultSetMetaData rm = rs.getMetaData(); int columnCount = rm.getColumnCount();//獲取字段數 //遍歷結果集 while(rs.next()) { Class<? extends Object> cla = t.getClass();//獲取類對象 T newInstance=(T)cla.newInstance();//獲取類的對象 //一個for循環封裝一條記錄的全部值 for(int i=1;i<=columnCount;i++) { String columnName = rm.getColumnName(i);//獲取字段名 //獲取字段對應的setter方法 String methodName="set"+columnName.substring(0, 1).toUpperCase()+columnName.substring(1); String columnClassName = rm.getColumnClassName(i);//獲取字段java類型的徹底限定名 //建立方法對象 Method method = cla.getDeclaredMethod(methodName, Class.forName(columnClassName)); method.invoke(newInstance,rs.getObject(columnName));//調用setter方法,執行對象屬性賦值 } list.add(newInstance);//將對象加入集合 } } catch (Exception e) { e.printStackTrace(); }finally { //關流 JDBCHelper.close(ps,rs); } return list; } /** * 該方法封裝了MySQL數據庫的DML操做 * 若是要實現事務: * 事務的開啓,關閉,回滾,及鏈接對象的關閉等操做 * 使用者經過JDBCHelper.getConnection()獲取鏈接對象,經過鏈接對象並在外部聲明 * 外部獲取的鏈接對象與本方法使用的鏈接對象,在同一線程類,是同一個對象 * * @param sql 要執行的SQL語句 * @param objs SQL語句中的參數 * @return 成功執行返回影響的記錄條數,不然返回0 * @throws SQLException */ public static Integer executeDML(String sql,Object...objs) { //聲明jdbc變量 Connection conn =null; PreparedStatement ps =null; Integer i =0; try{ conn = JDBCHelper.getConnection(); ps = conn.prepareStatement(sql); //給佔位符賦值 if(objs!=null) { for(int j=0;j<objs.length;j++) { ps.setObject((j+1), objs[j]); } } //執行SQL語句 i = ps.executeUpdate(); }catch(SQLException e) { e.printStackTrace(); }finally { //關流 JDBCHelper.close(ps); } return i; } /** * 關流的方法,接收任意多個任意類型的流對象 * 若是關閉的流對象有關閉的前後順序 * 請將要先關閉的流對象放在前方 * * 全部流對象的頂級父接口都是AutoCloseable * @param t 要關閉的流對象,能夠是一個或多個(也能夠是零個) * */ private static <T>void close(T...t){ //循環關流 for(T tmp:t) { //關閉流對象 if(tmp instanceof AutoCloseable) { try { ((AutoCloseable)tmp).close(); } catch (Exception e) { e.printStackTrace(); } } } } }