JAVA【操作BLOB类型字段】【批量操作】

27 篇文章 1 订阅
8 篇文章 0 订阅

目录

 一、如何使用preparedstatement流插入图片

二、如何使用preparedstatement流查询图片

三、使用preparestatement实现批量数据操作 

1.使用statement 

2.使用preparedstatement 

3.使用addbanch

4.设置不允许自动提交数据


 

MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。

MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

类型最大(单位:字节)
TinyBlob255
Blob65k
MediumBlob16M
LongBlob4G

 一、如何使用preparedstatement流插入图片

对于图片之类的文件我们可以使用流插入的形式将我们的文件传入我们的MySQL数据库

注:下面的JDBCUtils.getConnection()是我们之前已经封装过的方法

closeResource 也是我们已经封装过的方法

JAVA【JDBC】【使用PreparedStatement操作数据库】_桜キャンドル淵的博客-CSDN博客

中的二中的封装连接和关闭数据库资源

//向数据表customers中插入Blob类型的字段
	@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, "cuishiyuan@qq.com");
		ps.setObject(3,"1992-09-08");
		FileInputStream is = new FileInputStream(new File("test.jpg"));
		ps.setBlob(4, is);
		
		ps.execute();
		
		JDBCUtils.closeResource(conn, ps);
		
	}

 如果是修改的话就把上面代码中的SQL语句的insert改成update再做一些修改即可

二、如何使用preparedstatement流查询图片

使用SQL查询并且将数据库中的照片保存下来,我们可以使用流的方式将我们查询到的图片文件保存到本地。

这是我们要查询的表的结构 

 

//查询数据表customers中Blob类型的字段
	@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.setInt(1, 24);
			rs = ps.executeQuery();
			if(rs.next()){
	//			方式一:
	//			int id = rs.getInt(1);
	//			String name = rs.getString(2);
	//			String email = rs.getString(3);
	//			Date birth = rs.getDate(4);
				//方式二:
				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类型的字段下载下来,以文件的方式保存在本地
				Blob photo = rs.getBlob("photo");
				is = photo.getBinaryStream();
				fos = new FileOutputStream("龙叔说.jpg");
				byte[] buffer = new byte[1024];
				int len;
				while((len = is.read(buffer)) != -1){
					fos.write(buffer, 0, len);
				}
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			
			try {
				if(is != null)
					is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				if(fos != null)
					fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			JDBCUtils.closeResource(conn, ps, rs);
		}
		
		
	}

  

我们的图片图片也能够正常地打开和查看。 

 

如果我们上面插入的图片超出了我们之前表格的blob的最大限制,是会上传失败的。 

实际使用中根据需要存入的数据大小定义不同的BLOB类型。

需要注意的是:如果存储的文件过大,数据库的性能会下降。

如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

 

三、使用preparestatement实现批量数据操作 

update、delete本身就具有批量操作的效果

此时的批量操作主要指的是批量插入,使用preparedstatement如何实现更高效的批量插入?

题目:向goods表中插入20000条数据
CREATE TABLE goods(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(25)
);

 

1.使用statement 

//方式一:使用Statement
  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.execute(sql);
  }

2.使用preparedstatement 

//批量插入的方式二:使用PreparedStatement
	@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);
				
				ps.execute();
			}
			
			long end = System.currentTimeMillis();
			
			System.out.println("花费的时间为:" + (end - start));//20000:3129
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.closeResource(conn, ps);
			
		}
		
	}

 

 

 

PreparedStatement 能最大可能提高性能:

DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。

 

3.使用addbanch

就如同我们之前在io流中的一样,我们可以读取一批数据然后统一写入磁盘一样,这种方式减少了对于磁盘的io读写,同样的,我们可以通过类似的方式来提高对于MySQL的批量插入效率。

由于我们的MySQL默认是不支持批处理的,所以我们需要在我们的配置文件中加入这个参数来开启批处理

 

 

?rewriteBatchedStatements=true

JAVA【JDBC】_桜キャンドル淵的博客-CSDN博客

可以参考上面博客中的方法五来修改配置文件

在mysql.jar 5.1.7版本及之前的版本是不支持批量操作的,在5.1.37版本之后才会支持 

@Test
	public void testInsert2() {
		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();
				//每隔500次执行一次
				if(i % 500 == 0){
					//2.执行batch
					ps.executeBatch();
					
					//3.清空batch
					ps.clearBatch();
				}
				
			}
			
			long end = System.currentTimeMillis();
			
			System.out.println("花费的时间为:" + (end - start));//20000:3129 -- 446
		} catch (Exception e) {								
			e.printStackTrace();
		}finally{
			JDBCUtils.closeResource(conn, ps);
			
		}
		
	}

 

4.设置不允许自动提交数据

像truncate table之类的DDL操作会自动地进行数据提交,而delete from之类的DML操作可以实现数据的回滚,前提是要设置过set autocommit=false,因为默认情况下DML的增删改也是会自动提交的。

MySQL【创建和管理表】_桜キャンドル淵的博客-CSDN博客

中的六、清空表

我们可以在获取连接数据库的时候不着急地去提交,而是把数据都传完之后再去提交。 

//批量插入的方式四:设置连接不允许自动提交数据
	@Test
	public void testInsert3() {
		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));
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.closeResource(conn, ps);
			
		}
		
	}

 

 

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桜キャンドル淵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值