1. 程式人生 > >JavaEE之JDBC進階使用

JavaEE之JDBC進階使用

JDBC

JDBC批處理

1、為什麼需要批處理?

之前:一次操作只能傳送一條sql語句到資料庫伺服器,效率並不高!如果要插入2000條記錄,那麼必須傳送2000條sql語句。

如果IO流的話,一次寫出一個位元組,顯然效率效率並不高,所以可以使用快取位元組陣列提高每次寫出的效率。

現在:插入2000條記錄,但現在使用sql快取區,一次傳送多條sql到資料庫伺服器執行。這種做法就叫做批處理。

2、JDBC批處理的API

        statement 批處理:

                  void  addBatch(String sql)   將sql語句新增到緩衝區

                  int[]   executeBatch()       執行批處理命令  傳送所有的sql語句

                  void    clearBatch()  清空快取區

        PreparedStatement批處理:               

                 void       addBatch() 新增引數到快取區

                 int[]        executeBatch() 執行批處理命令。 傳送所有快取區的sql

                 void        clearBatch()  清空sql快取區

現進行測試:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
/**
 * 同時插入2000條資料
 * @author APPle
 * 結論:
 * 1) mysql資料庫不支援PreparedStatement優化,而且不支援批處理優化
 * 2) oracle資料庫即支援PreparedStatement優化,也支援批處理優化   
 *
 */
public class Demo1 {
	
	public static void main(String[] args) {
		//testByStaement();
		//testByStaementBatch();
		//testByPreparedStaement();
		//testByPreparedStaementBatch();
		
		testTime();
	}
	
	/**
	 * 測試執行速度
	 */
	public static void testTime(){
		long start = System.currentTimeMillis();
		//testByStaement();
		//testByStaementBatch();
		//testByPreparedStaement();
		testByPreparedStaementBatch();
		long end = System.currentTimeMillis();
		System.out.println("耗時為:"+(end-start));
	}

	/**
	 * 沒有批處理的Statement的情況
	 * mysql: 耗時為:7838   oracle:耗時為:6580
	 */
	public static void testByStaement(){
		Connection conn = null;
		Statement stmt = null;
		try{
			conn = JdbcUtil.getConnection();
			stmt = conn.createStatement();
			for(int i=1;i<=2000;i++){
				stmt.executeUpdate("INSERT INTO student VALUES("+i+",'張三',20,'男')");
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(stmt, conn);
		}
	}
	
	
	/**
	 * 使用批處理的Statement的情況
	 * mysql: 耗時為:9097  oracle:耗時為:5477
	 */
	public static void testByStaementBatch(){
		Connection conn = null;
		Statement stmt = null;
		try{
			conn = JdbcUtil.getConnection();
			stmt = conn.createStatement();
			for(int i=1;i<=2000;i++){
				//把sql新增到快取區
				stmt.addBatch("INSERT INTO student VALUES("+i+",'張三',20,'男')");
				//每20條傳送sql
				if(i%20==0){
					//執行批處理命令
					stmt.executeBatch();
					//清空快取區
					stmt.clearBatch();
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(stmt, conn);
		}
	}
	
	/**
	 * 沒有批處理的PrepaedStatement的情況
	 * mysql: 耗時為:9051 oracle:耗時為:4161
	 */
	public static void testByPreparedStaement(){
		Connection conn = null;
		PreparedStatement stmt = null;
		try{
			conn = JdbcUtil.getConnection();
			stmt = conn.prepareStatement("INSERT INTO student VALUES(?,?,?,?)");
			for(int i=1;i<=2000;i++){
				//引數賦值
				stmt.setInt(1, i);
				stmt.setString(2, "張三");
				stmt.setInt(3, 20);
				stmt.setString(4, "男");
				//執行
				stmt.executeUpdate();
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(stmt, conn);
		}
	}
	
	
	/**
	 * 使用批處理的PrepaedStatement的情況
	 * mysql:耗時為:9379 oracle: 耗時為:1391
	 */
	public static void testByPreparedStaementBatch(){
		Connection conn = null;
		PreparedStatement stmt = null;
		try{
			conn = JdbcUtil.getConnection();
			stmt = conn.prepareStatement("INSERT INTO student VALUES(?,?,?,?)");
			for(int i=1;i<=2000;i++){
				//引數賦值
				stmt.setInt(1, i);
				stmt.setString(2, "張三");
				stmt.setInt(3, 20);
				stmt.setString(4, "男");
				//把引數新增到快取區
				stmt.addBatch();
				//每20次傳送一次引數
				if(i%20==0){
					//執行批處理命令
					stmt.executeBatch();
					//清空快取區的引數
					stmt.clearBatch();
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(stmt, conn);
		}
	}
	
}

測試結論: 

        1) mysql資料庫不支援PreparedStatement優化,而且不支援批處理優化

        2) oracle資料庫即支援PreparedStatement優化,也支援批處理優化   

3、JDBC讀取大檔案資料

                        mysql:

                                   字串:varchar  char     65535

                                   大文字資料: tinytext , longtext   ,text

                                   位元組:  bit 

                                   大位元組檔案:tinyblob(255byte),blob(64kb),MEDIUMBLOB(約16M) longblob(4GB)

                          oracle:

                                   字串: varchar2  char     65535

                                   大文字資料: clob

                                   位元組: bit

                                   大位元組檔案: blob
3.1 JDBC操作字元檔案
/**
 * 對大文字資料處理
 * @author APPle
 *
 */
public class Demo1 {

	/**
	 * 檔案儲存到資料中
	 */
	@Test
	public void testWrite(){
		Connection conn = null;
		PreparedStatement stmt = null;
		try{
			//獲取連線
			conn = JdbcUtil.getConnection();
			//建立PreparedStatement
			String sql = "INSERT INTO test1(content) VALUES(?)";
			stmt =conn.prepareStatement(sql);
			//設定引數
			/**
			 * 引數一: 引數位置
			 * 引數二: 輸入字元流
			 */
			/**
			 * 讀取本地檔案,返回輸入字元流
			 */
			FileReader reader = new FileReader(new File("e:/Demo1.java"));
			stmt.setClob(1, reader);
			//執行sql
			int count = stmt.executeUpdate();
			System.out.println("影響了"+count+"行");
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(conn, stmt, null);
		}
	}
	
	/**
	 * 從資料中讀取文字內容
	 */
	@Test
	public void testRead(){
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try{
			//獲取連線
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM test1 where id=?";
			stmt = conn.prepareStatement(sql);
			//設定引數
			stmt.setInt(1, 2);
			//執行sql,返回結果集
			rs = stmt.executeQuery();
			if(rs.next()){
				//方式一:當做字串取出資料
				/*
				String content = rs.getString("content");
				System.out.println(content);
				*/
				
				//方式二:返回輸入流形式
				Clob clob = rs.getClob("content");
				Reader reader = clob.getCharacterStream();
				//寫出到檔案中
				FileWriter writer = new FileWriter(new File("e:/Demo2.java"));
				char[] buf = new char[1024];
				int len = 0;
				while( (len=reader.read(buf))!=-1){
					writer.write(buf, 0, len);
				}
				//關閉流
				writer.close();
				reader.close();
			}
			
			
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(conn, stmt, rs);
		}
	}
}
3.2 JDBC操作位元組檔案
/**
 * 對位元組檔案處理
 * @author APPle
 *
 */
public class Demo2 {

	/**
	 * 檔案儲存到資料庫中
	 */
	@Test
	public void testWrite(){
		Connection conn = null;
		PreparedStatement stmt = null;
		try{
			//獲取連線
			conn = JdbcUtil.getConnection();
			String sql = "insert into test2(content) values(?)";
			stmt = conn.prepareStatement(sql);
			//設定引數
			/**
			 * 引數一:引數位置
			 * 引數二:輸入位元組流
			 */
			/**
			 * 讀取本地檔案
			 */
			InputStream in = new FileInputStream(new File("e:/abc.wmv"));
			//stmt.setBlob(1, in);
			stmt.setBinaryStream(1, in);
			//執行
			stmt.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(conn, stmt, null);
		}
	}
	
	/**
	 * 注意: mysql資料庫預設情況下,只能儲存不超過1m的檔案,由於max_allowed_packet變數的限制
	 *   可以修改: %mysql%/my.ini檔案, 修改或新增max_allowed_packet變數,然後重啟mysql即可!!
	 */
	

	/**
	 * 從資料中讀取位元組內容
	 */
	@Test
	public void testRead(){
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try{
			//獲取連線
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM test2 where id=?";
			//獲取PreparedStatement
			stmt = conn.prepareStatement(sql);
			//設定引數
			stmt.setInt(1, 1);
			//執行sql
			rs = stmt.executeQuery();
			if(rs.next()){
				//返回輸入流
				//InputStream in = rs.getBinaryStream("content");
				InputStream in = rs.getBlob("content").getBinaryStream();
				//寫出檔案中
				FileOutputStream out = new FileOutputStream(new File("e://3.jpg"));
				byte[] buf = new byte[1024];
				int len = 0;
				while((len=in.read(buf))!=-1){
					out.write(buf, 0, len);
				}
				//關閉流
				out.close();
				in.close();
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JdbcUtil.close(conn, stmt, rs);
		}
	}
}