JDBC第二篇PreparedStatment、批处理、处理二进制、自动主键等
yuyutoo 2024-11-04 16:02 4 浏览 0 评论
1.PreparedStatement对象
PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单
- Statement对象编译SQL语句时,如果SQL语句有变量,就需要使用分隔符来隔开,如果变量非常多,就会使SQL变得非常复杂。PreparedStatement可以使用占位符,简化sql的编写
- Statement会频繁编译SQL。PreparedStatement可对SQL进行预编译,提高效率,预编译的SQL存储在PreparedStatement对象中
- 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语句执行时,应避免向数据库一条条发送执行,采用批处理以提升执行效率
批处理有两种方式:
- Statement
- 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
相关推荐
- 【Socket】解决UDP丢包问题
-
一、介绍UDP是一种不可靠的、无连接的、基于数据报的传输层协议。相比于TCP就比较简单,像写信一样,直接打包丢过去,就不用管了,而不用TCP这样的反复确认。所以UDP的优势就是速度快,开销小。但是随之...
- 深入学习IO多路复用select/poll/epoll实现原理
-
Linux服务器处理网络请求有三种机制,select、poll、epoll,本文打算深入学习下其实现原理。0.结论...
- 25-1-Python网络编程-基础概念
-
1-网络编程基础概念1-1-基本概念1-2-OSI七层网络模型OSI(开放系统互联)七层网络模型是国际标准化组织(ISO)提出的网络通信分层架构,用于描述计算机网络中数据传输的过程。...
- Java NIO多路复用机制
-
NIO多路复用机制JavaNIO(Non-blockingI/O或NewI/O)是Java提供的用于执行非阻塞I/O操作的API,它极大地增强了Java在处理网络通信和文件系统访问方面的能力。N...
- Python 网络编程完全指南:从零开始掌握 Socket 和网络工具
-
Python网络编程完全指南:从零开始掌握Socket和网络工具在现代应用开发中,网络编程是不可或缺的技能。Python提供了一系列高效的工具和库来处理网络通信、数据传输和协议操作。本指南将从...
- Rust中的UDP编程:高效网络通信的实践指南
-
在实时性要求高、允许少量数据丢失的场景中,UDP(用户数据报协议)凭借其无连接、低延迟的特性成为理想选择。Rust语言凭借内存安全和高性能的特点,为UDP网络编程提供了强大的工具支持。本文将深入探讨如...
- Python 网络编程的基础复习:理解Socket的作用
-
计算机网络的组成部分在逻辑上可以划分为这样的结构五层网络体系应用层:应用层是网络协议的最高层,解决的是具体应用问题...
- 25-2-Python网络编程-TCP 编程示例
-
2-TCP编程示例应用程序通常通过“套接字”(socket)向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通信。Python语言提供了两种访问网络服务的功能。...
- linux下C++ socket网络编程——即时通信系统(含源码)
-
一:项目内容本项目使用C++实现一个具备服务器端和客户端即时通信且具有私聊功能的聊天室。目的是学习C++网络开发的基本概念,同时也可以熟悉下Linux下的C++程序编译和简单MakeFile编写二:需...
- Python快速入门教程7:循环语句
-
一、循环语句简介循环语句用于重复执行一段代码块,直到满足特定条件为止。Python支持两种主要的循环结构:for循环和while循环。...
- 10分钟学会Socket通讯,学不会你打我
-
Socket通讯是软硬件直接常用的一种通讯方式,分为TCP和UDP通讯。在我的职业生涯中,有且仅用过一次UDP通讯。而TCP通讯系统却经常写,正好今天写了一个TCP通讯的软件。总结一下内容软件使用C#...
- Python 高级编程之网络编程 Socket(六)
-
一、概述Python网络编程是指使用Python语言编写的网络应用程序。这种编程涉及到网络通信、套接字编程、协议解析等多种方面的知识。...
- linux网络编程Socket之RST详解
-
产生RST的三个条件:1.目的地为某端口的SYN到达,然而该端口上没有正在监听的服务器;2.TCP想取消一个已有的连接;3.TCP接收到一个根本不存在的连接上的分节;现在模拟上面的三种情况:cl...
- Python中实现Socket通讯(附详细代码)
-
套接字(socket)是一种在计算机网络中进行进程间通信的方法,它允许不同主机上的程序通过网络相互通信。套接字是网络编程的基础,几乎所有的网络应用程序都使用某种形式的套接字来实现网络功能。套接字可以用...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)