JDBC小結
JDBC的性能最大的增進是減少JDBC驅動與數據庫之間的網絡通訊次數
Util.java(獲取連接器)
public Connection getConnection(){
Connection connection=null;
try {
//加載數據庫連接驅動
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/數據庫名?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true";
String user="root";
String password="HengTian0.0";
connection= DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
Statement與PreparedStatement
-
關係:PreparedStatement繼承Statement接口,且它們都是接口
-
區別:
-
Statement用來執行靜態sql語句,同時同一時間一個Statement只能打開一個ResultSet對象,當只執行一次性sql語句的時候,開銷比PreparedStatement小
-
PreparedStatement是預編譯的,對於批量處理可以大大提高效率. 也叫JDBC存儲過程
-
傳遞給PreparedStatement對象的參數可以被強制進行類型轉換,使開發人員可以確保在插入或查詢數據時與底層的數據庫格式匹配。
-
無論多少次地使用同一個SQL命令,PreparedStatement都只對它解析和編譯一次。當使用Statement對象時,每次執行一個SQL命令時,都會對它進行解析和編譯。
-
PrepareStatement會先初始化SQL,先把這個SQL提交到數據庫中進行預處理,多次使用可提高效率。 Statement不會初始化,沒有預處理,沒次都是從0開始執行SQL
-
PrepareStatement可以使用佔位符"?",如:insert into table demo(name,id) values(?,?);
-
PrepareStatement可以用addBatch()方法將將要處理的語句預存起來
例一:
PreparedStatement ps = conn.prepareStatement( "INSERT into employees values (?, ?, ?)"); for (n = 0; n < 100; n++) { ps.setString(name[n]); ps.setLong(id[n]); ps.setInt(salary[n]); ps.executeUpdate(); }
例二:
PreparedStatement ps = conn.prepareStatement( "INSERT into employees values (?, ?, ?)"); for (n = 0; n < 100; n++) { ps.setString(name[n]); ps.setLong(id[n]); ps.setInt(salary[n]); ps.addBatch(); } ps.executeBatch();
在例 1中, PreparedStatement被用來多次執行INSERT語句. 在這裏, 執行了100次INSERT操作, 共有101次網絡往返.
其中,1次往返是預儲PreparedStatement, 另外100次往返執行每個迭代.
在例2中, 當在100次INSERT操作中使用addBatch()方法時, 只有兩次網絡往返.
1次往返是預儲PreparedStatement, 另一次是執行batch命令. 雖然Batch命令會用到更多的數據庫的CPU週期, 但是通過減少網絡往返,性能得到提高.記住, JDBC的性能最大的增進是減少JDBC驅動與數據庫之間的網絡通訊.次數
!使用批處理時要在url後面加rewriteBatchedStatements=true表示批量插入,如果不添加的話即使使用addbatch() ,executeBatch() 在後臺入庫的地方還是不會一次請求入庫而是多次請求入庫
//批量處理時最好取消自動提交,進行手動提交 connection.setAutoCommit(false);
批量添加的實例
public static void insertData(List<Map<String,String>> list,Logger log){ //獲取的數據 List <Map<String,String>> nlist= list; String upsql="update hrd_staff set position =? where id=?"; Iterator<Map<String,String>> iter= nlist.iterator(); Connection con= Utils.getCon(); int count=0; try { //在批量添加的時候注意事務提交方式 con.setAutoCommit(false); //PreparedStatement方法的使用 PreparedStatement pstm = con.prepareStatement(upsql); while(iter.hasNext()){ count++; Map<String,String> map= iter.next(); String jon_name= map.get("job_name"); String uid= map.get("uid"); pstm.setString(1,jon_name); pstm.setString(2,uid); //添加到緩存中 pstm.addBatch(); // 如果數據量很大,不能一次性批量添加所以我們要分批次添加,這裏就是300條一次 if(count%300==0){ //持久化 int []res=pstm.executeBatch(); //提交事務,持久化數據 con.commit(); pstm.clearBatch(); log.info("300整除插入結果: "+res.length); } } //小於300條的在這裏持久化 int []ress= pstm.executeBatch(); //事務提交持久化 con.commit(); pstm.clearBatch(); log.info("插入數據結果:"+ress.length); } catch (SQLException e) { try { con.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); }finally{ try { if(null!=con){ con.close(); con.setAutoCommit(true); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
批量添加步驟最後總結:
-
url中添加rewriteBatchedStatements=true,如:
String url="jdbc:mysql://localhost:3306/MyTestBase?rewriteBatchedStatements=true;
- 將connection的自動提交關閉
con=JdbcUtil.getConnection();//自己實現的工具類,獲取connection對象 con.setAutoCommit(false);
-
-
ResultSet
- Statement和PreparedStatement中都可以傳入兩個參數:ResultSetType和ResultSetConcurrency(名字自己取的,意思差不多,type在前,concurrency在後,但是都可單獨傳入)
ResultSet方法 | 作用 |
---|---|
public boolean next() | 順序獲取查詢記錄 |
public void beforeFrist() | 將遊標移動到第一行之前 |
public void afterLast() | 將遊標移到最後一行之後 |
public void first() | 將遊標移動到結果集的第一行 |
public void last() | 將遊標移動到結果集的最後一行 |
public boolean isAfterLast() | 判斷遊標是否在最後一行之後 |
public boolean isBeforefirst() | 判斷遊標是否在最後一行之前 |
public boolean isFirst() | 判斷遊標是否在結果集的第一行 |
public boolean isLast() | 判斷遊標是否在結果集的最後一行 |
public int getRow() | 得到當前遊標所指行的行號,行號從1開始。如果結果集沒有行,返回0 |
public boolean absolute(int row) | 將遊標移動到參數row所指的行號 |
public boolean previous() | 將遊標向上移動,該方法返回boolean型數據,當移動到結果集第一行的前面返回false |
type取值 | 作用 |
---|---|
ResultSet.TYPE_FORWARD_ONLY | 結果集的遊標只能向下滾動 |
ResultSet.TYPE_SCROLL_INSENSITIVE | 結果集的遊標可以上下移動,當數據庫變化時,當前結果集不變 |
ResultSet.TYPE_SCROLL_SENSITIVE | 返回可滾動的結果集,當數據庫變化時,結果集同步變化 |
Concurrency取值 | 作用 |
---|---|
ResultSet.CONCUR_READ_ONLY | 不能用結果集更新數據庫中的表 |
ResultSet.CONCUR_UPDATABLE | 能用結果集更新數據庫中的表 |
-
ResultSetMetaData
ResultSet rs=ps.executeQuery(); ResultSetMetaData metaData=rs.getMetaData();
ResultSetMetaData中保存的結果集的列,如:姓名,班級等
-
CachedRowSetImpl
CachedRowSetImpl可以保存ResultSet對象中的數據,並且CachedRowSetImpl不依賴connection對象,因此,查詢CachedRowSetImpl時可以關閉和數據庫的連接