百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

JDBC第二篇PreparedStatment、批处理、处理二进制、自动主键等

sinye56 2024-10-04 23:53 7 浏览 0 评论

1.PreparedStatement对象


PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单

  1. Statement对象编译SQL语句时,如果SQL语句有变量,就需要使用分隔符来隔开,如果变量非常多,就会使SQL变得非常复杂。PreparedStatement可以使用占位符,简化sql的编写
  2. Statement会频繁编译SQL。PreparedStatement可对SQL进行预编译,提高效率,预编译的SQL存储在PreparedStatement对象中
  3. PreparedStatement防止SQL注入。【Statement通过分隔符'++',编写永等式,可以不需要密码就进入数据库】
//模拟查询id为2的信息
String id = "2";
Connection connection = UtilsDemo.getConnection();
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement preparedStatement = connection.preparedStatement(sql);
//第一个参数表示第几个占位符【也就是?号】,第二个参数表示值是多少
preparedStatement.setString(1,id);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
 System.out.println(resultSet.getString("name"));
}
//释放资源
UtilsDemo.release(connection, preparedStatement, resultSet);

2.批处理

当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条发送执行,采用批处理以提升执行效率

批处理有两种方式:

  1. Statement
  2. PreparedStatement


通过executeBath()方法批量处理执行SQL语句,返回一个int[]数组,该数组代表各句SQL的返回值

以下代码是以Statement方式实现批处理

/*
* Statement执行批处理
*
* 优点:
* 可以向数据库发送不同的SQL语句
* 缺点:
* SQL没有预编译
* 仅参数不同的SQL,需要重复写多条SQL
* */
Connection connection = UtilsDemo.getConnection();
Statement statement = connection.createStatement();
String sql1 = "UPDATE users SET name='zhongfucheng' WHERE id='3'";
String sql2 = "INSERT INTO users (id, name, password, email, birthday)" +
 " VALUES('5','nihao','123','ss@qq.com','1995-12-1')";
//将sql添加到批处理
statement.addBatch(sql1);
statement.addBatch(sql2);
//执行批处理
statement.executeBatch();
//清空批处理的sql
statement.clearBatch();
UtilsDemo.release(connection, statement, null);

以下方式以PreparedStatement方式实现批处理

/*
* PreparedStatement批处理
* 优点:
* SQL语句预编译了
* 对于同一种类型的SQL语句,不用编写很多条
* 缺点:
* 不能发送不同类型的SQL语句
*
* */
Connection connection = UtilsDemo.getConnection();
String sql = "INSERT INTO test(id,name) VALUES (?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 1; i <= 205; i++) {
 preparedStatement.setInt(1, i);
 preparedStatement.setString(2, (i + "zhongfucheng"));
 //添加到批处理中
 preparedStatement.addBatch();
 if (i %2 ==100) {
 //执行批处理
 preparedStatement.executeBatch();
 //清空批处理【如果数据量太大,所有数据存入批处理,内存肯定溢出】
 preparedStatement.clearBatch();
 }
}
//不是所有的%2==100,剩下的再执行一次批处理
preparedStatement.executeBatch();
//再清空
preparedStatement.clearBatch();
UtilsDemo.release(connection, preparedStatement, null);

3.处理大文本和二进制数据

clob和blob

  • clob用于存储大文本
  • blob用于存储二进制数据



MYSQL

MySQL存储大文本是用Test【代替clob】,Test又分为4类

  • TINYTEXT
  • TEXT
  • MEDIUMTEXT
  • LONGTEXT

同理blob也有这4类


下面用JDBC连接MySQL数据库去操作大文本数据和二进制数据

/*
*用JDBC操作MySQL数据库去操作大文本数据
*
*setCharacterStream(int parameterIndex,java.io.Reader reader,long length)
*第二个参数接收的是一个流对象,因为大文本不应该用String来接收,String太大会导致内存溢出
*第三个参数接收的是文件的大小
*
* */
public class Demo5 {
 @Test
 public void add() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = JdbcUtils.getConnection();
 String sql = "INSERT INTO test2 (bigTest) VALUES(?) ";
 preparedStatement = connection.prepareStatement(sql);
 //获取到文件的路径
 String path = Demo5.class.getClassLoader().getResource("BigTest").getPath();
 File file = new File(path);
 FileReader fileReader = new FileReader(file);
 //第三个参数,由于测试的Mysql版本过低,所以只能用int类型的。高版本的不需要进行强转
 preparedStatement.setCharacterStream(1, fileReader, (int) file.length());
 if (preparedStatement.executeUpdate() > 0) {
 System.out.println("插入成功");
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } finally {
 JdbcUtils.release(connection, preparedStatement, null);
 }
 }
 /*
 * 读取大文本数据,通过ResultSet中的getCharacterStream()获取流对象数据
 * 
 * */
 @Test
 public void read() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = JdbcUtils.getConnection();
 String sql = "SELECT * FROM test2";
 preparedStatement = connection.prepareStatement(sql);
 resultSet = preparedStatement.executeQuery();
 if (resultSet.next()) {
 Reader reader = resultSet.getCharacterStream("bigTest");
 FileWriter fileWriter = new FileWriter("d:\\abc.txt");
 char[] chars = new char[1024];
 int len = 0;
 while ((len = reader.read(chars)) != -1) {
 fileWriter.write(chars, 0, len);
 fileWriter.flush();
 }
 fileWriter.close();
 reader.close();
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 JdbcUtils.release(connection, preparedStatement, resultSet);
 }
 }

/*
* 使用JDBC连接MYsql数据库操作二进制数据
* 如果我们要用数据库存储一个大视频的时候,数据库是存储不到的。
* 需要设置max_allowed_packet,一般我们不使用数据库去存储一个视频
* */
public class Demo6 {
 @Test
 public void add() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = JdbcUtils.getConnection();
 String sql = "INSERT INTO test3 (blobtest) VALUES(?)";
 preparedStatement = connection.prepareStatement(sql);
 //获取文件的路径和文件对象
 String path = Demo6.class.getClassLoader().getResource("1.wmv").getPath();
 File file = new File(path);
 //调用方法
 preparedStatement.setBinaryStream(1, new FileInputStream(path), (int)file.length());
 if (preparedStatement.executeUpdate() > 0) {
 System.out.println("添加成功");
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } finally {
 JdbcUtils.release(connection, preparedStatement, null);
 }
 }
 @Test
 public void read() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = JdbcUtils.getConnection();
 String sql = "SELECT * FROM test3";
 preparedStatement = connection.prepareStatement(sql);
 resultSet = preparedStatement.executeQuery();
 //如果读取到数据,就把数据写到磁盘下
 if (resultSet.next()) {
 InputStream inputStream = resultSet.getBinaryStream("blobtest");
 FileOutputStream fileOutputStream = new FileOutputStream("d:\\aa.jpg");
 int len = 0;
 byte[] bytes = new byte[1024];
 while ((len = inputStream.read(bytes)) > 0) {
 fileOutputStream.write(bytes, 0, len);
 }
 fileOutputStream.close();
 inputStream.close();
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 JdbcUtils.release(connection, preparedStatement, null);
 }
 }

Oracle

下面用JDBC连接Oracle数据库去操作大文本数据和二进制数据

//使用JDBC连接Oracle数据库操作二进制数据
/*
* 对于Oracle数据库和Mysql数据库是有所不同的。
* 1.Oracle定义了BLOB字段,但是这个字段不是真正地存储二进制数据
* 2.向这个字段存一个BLOB指针,获取到Oracle的BLOB对象,把二进制数据放到这个指针里面,指针指向BLOB字段
* 3.需要事务支持
*
* */
public class Demo7 {
 @Test
 public void add() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = UtilsDemo.getConnection();
 //开启事务
 connection.setAutoCommit(false);
 //插入一个BLOB指针
 String sql = "insert into test4(id,image) values(?,empty_blob())";
 preparedStatement = connection.prepareStatement(sql);
 preparedStatement.setInt(1, 1);
 preparedStatement.executeUpdate();
 //把BLOB指针查询出来,得到BLOB对象
 String sql2 = "select image from test4 where id= ? for update";
 preparedStatement = connection.prepareStatement(sql2);
 preparedStatement.setInt(1, 1);
 resultSet = preparedStatement.executeQuery();
 if (resultSet.next()) {
 //得到Blob对象--当成是Oracle的Blob,不是JDBC的,所以要强转[导的是oracle.sql.BLOB包]
 BLOB blob = (BLOB) resultSet.getBlob("image");
 //写入二进制数据
 OutputStream outputStream = blob.getBinaryOutputStream();
 //获取到读取文件读入流
 InputStream inputStream = Demo7.class.getClassLoader().getResourceAsStream("01.jpg");
 int len=0;
 byte[] bytes = new byte[1024];
 while ((len = inputStream.read(bytes)) > 0) {
 outputStream.write(bytes, 0, len);
 }
 outputStream.close();
 inputStream.close();
 connection.setAutoCommit(true);
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 UtilsDemo.release(connection, preparedStatement, null);
 }
 }
 @Test
 public void find() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = UtilsDemo.getConnection();
 String sql = "SELECT * FROM test4 WHERE id=1";
 preparedStatement = connection.prepareStatement(sql);
 resultSet = preparedStatement.executeQuery();
 if (resultSet.next()) {
 //获取到BLOB对象
 BLOB blob = (BLOB) resultSet.getBlob("image");
 //将数据读取到磁盘上
 InputStream inputStream = blob.getBinaryStream();
 FileOutputStream fileOutputStream = new FileOutputStream("d:\\zhongfucheng.jpg");
 int len=0;
 byte[] bytes = new byte[1024];
 while ((len = inputStream.read(bytes)) > 0) {
 fileOutputStream.write(bytes, 0, len);
 }
 inputStream.close();
 fileOutputStream.close();
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 UtilsDemo.release(connection, preparedStatement, null);
 }
 }
}

对于JDBC连接Oracle数据库操作CLOB数据,我就不再重复了,操作跟BLOB几乎相同


4.获取数据库的自动主键列

为什么要获取数据库的自动主键列数据?

应用场景:

有一张老师表,一张学生表。现在来了一个新的老师,学生要跟着新老师上课。

我首先要知道老师的id编号是多少,学生才能知道跟着哪个老师学习【学生外键参照老师主键】。


@Test
public void test() {
 Connection connection = null;
 PreparedStatement preparedStatement = null;
 ResultSet resultSet = null;
 try {
 connection = JdbcUtils.getConnection();
 String sql = "INSERT INTO test(name) VALUES(?)";
 preparedStatement = connection.prepareStatement(sql);
 preparedStatement.setString(1, "ouzicheng");
 if (preparedStatement.executeUpdate() > 0) {
 //获取到自动主键列的值
 resultSet = preparedStatement.getGeneratedKeys();
 if (resultSet.next()) {
 int id = resultSet.getInt(1);
 System.out.println(id);
 }
 }
 } catch (SQLException e) {
 e.printStackTrace();
 } finally {
 JdbcUtils.release(connection, preparedStatement, null);
 }
} 

5.调用数据库的存储过程

调用存储过程的语法:

{call <procedure-name>[(<arg1>,<arg2>, ...)]}


调用函数的语法:

{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}


如果是Output类型的,那么在JDBC调用的时候是要注册的。如下代码所示:

/*
jdbc调用存储过程
delimiter $
 CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam varchar(255))
 BEGIN
 SELECT CONCAT('zyxw---', inputParam) into inOutParam;
 END $
delimiter ;
*/
//我们在JDBC调用存储过程,就像在调用方法一样
public class Demo9 {
 public static void main(String[] args) {
 Connection connection = null;
 CallableStatement callableStatement = null;
 try {
 connection = JdbcUtils.getConnection();
 callableStatement = connection.prepareCall("{call demoSp(?,?)}");
 callableStatement.setString(1, "nihaoa");
 //注册第2个参数,类型是VARCHAR
 callableStatement.registerOutParameter(2, Types.VARCHAR);
 callableStatement.execute();
 //获取传出参数[获取存储过程里的值]
 String result = callableStatement.getString(2);
 System.out.println(result);
 } catch (Exception e) {
 e.printStackTrace();
 }finally {
 try {
 connection.close();
 callableStatement.close();
 } catch (SQLException e) {
 e.printStackTrace();
 }
 }
 }
} 

参考资料:

----------------------------------------------------------------------------------过程
#修改mysql语句的结果符为//
mysql > delimiter //
#定义一个过程,获取users表总记录数,将10设置到变量count中
create procedure simpleproc(out count int)
begin
 select count(id) into count from users;
end
//
#修改mysql语句的结果符为;
mysql > delimiter ;
#调用过程,将结果覆给变量a,@是定义变量的符号
call simpleproc(@a);
#显示变量a的值
select @a;
//以下是Java调用Mysql的过程
 String sql = "{call simpleproc(?)}";
 Connection conn = JdbcUtil.getConnection();
 CallableStatement cstmt = conn.prepareCall(sql);
 cstmt.registerOutParameter(1,Types.INTEGER);
 cstmt.execute();
 Integer count = cstmt.getInt(1);
 System.out.println("共有" + count + "人");
----------------------------------------------------------------------------------函数
#修改mysql语句的结果符为//
mysql > delimiter //
#定义一个函数,完成字符串拼接
create function hello( s char(20) ) returns char(50) 
return concat('hello,',s,'!');
//
#修改mysql语句的结果符为;
mysql > delimiter ;
#调用函数
select hello('world');
//以下是Java调用Mysql的函数
 String sql = "{? = call hello(?)}";
 Connection conn = JdbcUtil.getConnection();
 CallableStatement cstmt = conn.prepareCall(sql);
 cstmt.registerOutParameter(1,Types.VARCHAR);
 cstmt.setString(2,"zhaojun");
 cstmt.execute();
 String value = cstmt.getString(1);
 System.out.println(value);
 JdbcUtil.close(cstmt);
 JdbcUtil.close(conn);

原文地址:https://dwz.cn/9N2ogJ1z

作者:Java3y

相关推荐

Linux中10大常用命令之sort使用案例

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言Linux中的sort命令用于对文本文件的内容进行排序。本教程向您展示了sort...

java开发常用的Linux命令,高频的没你想象的多

Linux的命令非常多,多到有些使用的场景你工作两三年也没有遇到过,工作三四年才能遇到(Linux内核开发,Shell脚本开发,嵌入式开发、、、),但这个不是今天分享的重点,今天分享的重点是Java开...

linux常用命令(收藏版)

linux小白注意啦,给大家分享一点干货,请笑纳!1.关机命令shutdown-hnow关闭系统(1)init0关闭系统(2),0为系统的进程号telinit0关闭系统(3)shutdo...

延续Win10三年需付超3000元!微软彻底封堵:删除绕过Win11系统要求教程、将第三方工具标记为恶意软件

一切都是为了用户能够正规地升级到Windows11。整理|屠敏出品|CSDN(ID:CSDNnews)距离Windows10退役仅剩8个月,微软最近这段时间,终是忍不住接连出手了...

敲完就让你提桶跑路的Linux命令

不谨慎可能就会让你提桶的Linux命令!!!删除文件rm-rf该命令是删除文件或文件夹等最快的方式之一。删除后的内容很难恢复,如果删除系统文件可能会导致系统崩坏。˃rm-rf/#强制删除根...

超级蠕虫,累计感染40万台服务器,让Linux内核服务器感染两年

最近著名安全公司ESET发布安全报告,报告分析了其对一个超级蠕虫Ebury的15年追踪分析。在15年中该病毒持续感染了40万台服务器,曾经在2011年(2009年)攻克了Linux内核维护站点kern...

linux redhat破解密码

适用于RedhatCentosFedora1.开机选择第一个启动项,按e进入编辑模式2.在启动项编辑模式找到linux16开头的文件,按ctrl+e快速定位到该行的行末,输入空格rd.break...

慎用!Linux最危险的10个命令!

Linux是一个强大而灵活的操作系统,它提供了许多功能丰富的命令和工具,让用户可以方便地管理和控制系统。但是,有些命令如果不小心或不知情地使用,可能会造成严重的后果,甚至导致系统崩溃或数据丢失。因此,...

Linux文件和目录删除

今天只讲一个命令,这个命令已经让万千运维人既爱又恨。rm删除文件或者目录基本用法:-i显示删除提示信息-f强制删除文件-r进行目录的递归删除在公司里为了保证数据安全,一般会创建一个alias...

给你的Linux系统穿上“防弹衣”:安全加固全攻略

为什么Linux系统需要安全加固在当今数字化时代,Linux系统以其开源、稳定、高效等特性,在服务器领域占据着举足轻重的地位。无论是大型互联网公司的核心业务,还是中小企业的日常运营,都离不开L...

一天一个Linux命令:文件操作「删」rm

命令:rm-rf文件名(慎用,慎用,慎用)rm(选项)(参数)命令功能:rm-rf是一条UNIX系统下的文件删除命令,作用是无提示地强制递归删除一个目录中的一个或多个文件或目录,如果没有使用...

Linux下通过 rm -f 删除大量文件时报错:Argument list too long

问题现象云服务器ECSLinux下通过rm-f删除大量的小文件时出现类似如下错误信息:-bash:?/bin/rm:?Argument?list?too?long如下图所示:问题原因如?待删...

这10个Linux命令太危险,千万慎用!数据毁灭的瞬间只需一个回车

你好,这里是网络技术联盟站,我是瑞哥。Linux系统,以其开源自由的特性,吸引了无数开发者和科技爱好者。其强大的命令行工具赋予了用户前所未有的控制能力。然而,正如俗话所说,“能力越大,责任越大”。某些...

Linux的10大危险命令,用过的运维都很刑

rm-rf命令该命令可能导致不可恢复的系统崩坏。˃rm-rf/#强制删除根目录下所有东西。˃rm-rf*#强制删除当前目录的所有文件。˃rm-rf.#强制删除当前...

Linux环境变量设置与查看全攻略

Linux环境变量设置与查看全攻略在Linux系统中,环境变量是用于定义系统和用户级设置的一种方法,它可以影响程序的行为和系统的运行方式。了解如何设置和查看环境变量对于Linux用户来说是非常重要的技...

取消回复欢迎 发表评论: