JDBC(2)-操作BLOB類型字段和批量插入


一、操作BLOB類型字段

1. MySQL BLOB類型

  • MySQL中,BLOB是一個二進制大型對象,是一個可以存儲大量數據的容器,它能容納不同大小的數據。

  • 插入BLOB類型的數據必須使用PreparedStatement,因為BLOB類型的數據無法使用字符串拼接寫的。

  • MySQL的四種BLOB類型(除了在存儲的最大信息量上不同外,他們是等同的)

  • 實際使用中根據需要存入的數據大小定義不同的BLOB類型。

  • 需要注意的是:如果存儲的文件過大,數據庫的性能會下降。

  • 如果在指定了相關的Blob類型以后,還報錯:xxx too large,那么在mysql的安裝目錄下,找my.ini文件加上如下的配置參數: max_allowed_packet=16M。同時注意:修改了my.ini文件之后,需要重新啟動mysql服務

2. 向數據表中插入大數據類型

其中的配置信息和上次使用的一樣

@Test
	public void testInsert() throws Exception {
		Connection conn = JDBCUtils.getConnection();
		
		String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";

		PreparedStatement ps = conn.prepareStatement(sql);
		
		ps.setObject(1, "馮寶寶");
		ps.setObject(2, "bao@qq.com");
		ps.setObject(3, "1000-10-10");
		// 圖片
		FileInputStream is = new FileInputStream(new File("timg.jpg"));
		ps.setBlob(4, is);
		// 執行
		ps.execute();
		
		JDBCUtils.closeResource(conn, ps);
	}

3. 修改數據表中的Blob類型字段

Connection conn = JDBCUtils.getConnection();
String sql = "update customers set photo = ? where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);

// 填充占位符
// 操作Blob類型的變量
FileInputStream fis = new FileInputStream("coffee.png");
ps.setBlob(1, fis);
ps.setInt(2, 25);

ps.execute();

fis.close();
JDBCUtils.closeResource(conn, ps);

4. 從數據表中讀取大數據類型

@Test
	public void testQuery() {
		Connection conn = null;
		PreparedStatement ps = null;
		InputStream is = null;
		FileOutputStream fos = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			
			String sql = "select id , name , email , birth , photo from customers where id = ?";
		
			ps = conn.prepareStatement(sql);
			
			ps.setObject(1, 19);
			// 有結果集
			rs = ps.executeQuery();
			if(rs.next()) {
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String  email = rs.getString("email");
				Date birth = rs.getDate("birth");
				
				Customer cust = new Customer(id , name , email , birth);
				System.out.println(cust);
				
				// 將Blob字段下載下來,保存到本地,除了調用了getBinaryStream()方法,剩下的和二進制流差不多
				Blob photo = rs.getBlob("photo");
				 is = photo.getBinaryStream();
				 fos = new FileOutputStream("lin.jpg");
				byte[] buffer = new byte[1024];
				int len;
				while((len = is.read(buffer)) != -1) {
					fos.write(buffer , 0, len);
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			try {
				if(is != null)
					is.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			try {
				if(fos != null)
					fos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			JDBCUtils.closeResource(conn, ps, rs);
		}
	}

二、批量插入

1. 批量執行SQL語句

當需要成批插入或者更新記錄時,可以采用Java的批量更新機制,這一機制允許多條語句一次性提交給數據庫批量處理。通常情況下比單獨提交處理更有效率

JDBC的批量處理語句包括下面三個方法:

  • addBatch(String):添加需要批量處理的SQL語句或是參數;
  • executeBatch():執行批量處理語句;
  • clearBatch():清空緩存的數據

通常我們會遇到兩種批量執行SQL語句的情況:

  • 多條SQL語句的批量處理;
  • 一個SQL語句的批量傳參;

2. 例如:插入20000條數據

CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);

這個就不演示了,太low

Connection conn = JDBCUtils.getConnection();
Statement st = conn.createStatement();
for(int i = 1;i <= 20000;i++){
	String sql = "insert into goods(name) values('name_' + "+ i +")";
	st.executeUpdate(sql);
}

3. 方式一:使用PreparedStatement

JDBCUtils在上一篇寫過,獲取連接以及釋放連接

@Test
	public void testInsert() {
		
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			// 開始時間
			long start = System.currentTimeMillis();
			
			conn = JDBCUtils.getConnection();
			
			String sql = "insert into goods(name) values(?)";
			
			ps = conn.prepareStatement(sql);
			
			for(int i=1; i <= 20000; i++) {
				ps.setObject(1, "name_"+i);
				
				ps.execute();
			}
			
			// 結束時間
			long end = System.currentTimeMillis();
			
			System.out.println("花費的時間:"+(end-start)); //903016
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, ps);
		}
	}

可以看到,花費的時間是很長的

4. 方式二:xxxBatch()

需要准備:

  • mysql服務器默認是關閉批處理的,我們需要通過一個參數,讓mysql開啟批處理的支持,
    • ?rewriteBatchedStatements=true 寫在配置文件的url后面
  • 使用更新的mysql 驅動:mysql-connector-java-5.1.37-bin.jar
  • 使用 addBatch() / executeBatch() / clearBatch()

需要注意,因為之前用的mysql驅動是mysql-connector-java-5.1.7-bin.jar,所以先把這個

然后再重新導入mysql-connector-java-5.1.37-bin.jar這個

下面就可以寫代碼了,還是在方式一的基礎上:

@Test
	public void testInsert1() {
		
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			// 開始時間
			long start = System.currentTimeMillis();
			
			conn = JDBCUtils.getConnection();
			
			String sql = "insert into goods(name) values(?)";
			
			ps = conn.prepareStatement(sql);
			
			for(int i=1; i <= 20000; i++) {
				ps.setObject(1, "name_"+i);
				
				// 1. 攢sql
				ps.addBatch();
				
				if(i % 500 == 0) {
					// 2. 執行batch
					ps.executeBatch();
					
					// 3. 清空batch
					ps.clearBatch();
				}
				
			}
			
			// 結束時間
			long end = System.currentTimeMillis();
			
			System.out.println("花費的時間:"+(end-start)); //5399
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, ps);
		}
	}

花費的時間明顯少了很多

5. 方式三:終極版

  • 方式三:在方式二的基礎上操作
  • 使用Connection 的 setAutoCommit(false) / commit()
@Test
		public void testInsert2() {
			
			Connection conn = null;
			PreparedStatement ps = null;
			try {
				// 開始時間
				long start = System.currentTimeMillis();
				
				conn = JDBCUtils.getConnection();

				// 設置不允許自動提交數據
				conn.setAutoCommit(false);
				
				String sql = "insert into goods(name) values(?)";
				
				ps = conn.prepareStatement(sql);
				
				for(int i=1; i <= 20000; i++) {
					ps.setObject(1, "name_"+i);
					
					// 1. 攢sql
					ps.addBatch();
					
					if(i % 500 == 0) {
						// 2. 執行batch
						ps.executeBatch();
						
						// 3. 清空batch
						ps.clearBatch();
					}
				}
				// 提交數據
				conn.commit();
				
				// 結束時間
				long end = System.currentTimeMillis();
				
				System.out.println("花費的時間:"+(end-start)); //2223
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				JDBCUtils.closeResource(conn, ps);
			}
		}

速度幾乎又提升了一倍


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM