JDBC

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

      批量添加步驟最後總結:

      1. url中添加rewriteBatchedStatements=true,如:

        String url="jdbc:mysql://localhost:3306/MyTestBase?rewriteBatchedStatements=true;
        
        1. 將connection的自動提交關閉
        con=JdbcUtil.getConnection();//自己實現的工具類,獲取connection對象
        con.setAutoCommit(false);
        

        主要參考:https://blog.csdn.net/QH_JAVA/article/details/48245945

ResultSet

  1. 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 能用結果集更新數據庫中的表
  1. ResultSetMetaData

    ResultSet rs=ps.executeQuery();
    ResultSetMetaData metaData=rs.getMetaData();
    

    ResultSetMetaData中保存的結果集的列,如:姓名,班級等

  2. CachedRowSetImpl

    CachedRowSetImpl可以保存ResultSet對象中的數據,並且CachedRowSetImpl不依賴connection對象,因此,查詢CachedRowSetImpl時可以關閉和數據庫的連接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章