tags: JDBC


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();//清空批处理的sqlstatement.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 {@Testpublic 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()获取流对象数据* * */@Testpublic 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 {@Testpublic 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);}}@Testpublic 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 {@Testpublic 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);}}@Testpublic 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编号是多少,学生才能知道跟着哪个老师学习【学生外键参照老师主键】。


@Testpublic 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))BEGINSELECT 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个参数,类型是VARCHARcallableStatement.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)
beginselect 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);复制代码

如果您觉得这篇文章帮助到了您,可以给作者一点鼓励

JDBC第二篇 【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】...相关推荐

  1. java获取表主外键_通过 jdbc 分析数据库中的表结构和主键外键

    文章转自:http://ivan4126.blog.163.com/blog/static/20949109220137753214811/ 在某项目中用到了 hibernate ,大家都知道 hib ...

  2. java核心技术第四篇之JDBC第二篇

    01.JDBC连接池_连接池的概念: 1).什么是连接池:对于多用户程序,为每个用户单独创建一个Connection,会使程序降低效率.这时我们可以创建一个"容器", 这个容器中, ...

  3. 后端思维篇:手把手教你写一个并行调用模板

    前言 36个设计接口的锦囊中,也提到一个知识点:就是使用并行调用优化接口.所以接下来呢,就快马加鞭写第二篇:手把手教你写一个并行调用模板~ 一个串行调用的例子(App首页信息查询) Completio ...

  4. 利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇“自动运行函数”

    利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇"自动运行函数" 完整的项目链接: https://github.com/linxinloningg/51_chip ...

  5. 5G网络实现自动驾驶车联网——第二篇:5G网络内网穿透

    5G网络实现自动驾驶车联网--第二篇:5G网络内网穿透 大家好我是Jones,写博客记录一下工作的痕迹,同时也对工作做一个总结,才疏学浅,难免会有很多纰漏,还请大家批评指正,创业初期,欢迎技术和商务洽 ...

  6. JDBC中事务、批量操作、大数据类型、获取自动生成的主键、等用法

    1 事务的用法 事务的ACID属性: 通俗的说事务:指一组操作,要么都成功执行,要么都不执行-->原子性在所有的操作没有执行完毕之前,其他会话不能够看到中间改变的过程-->隔离性事务发生前 ...

  7. jdbc 3种获得mysql插入数据的自增字段值的方法_【JDBC】向数据表插入数据时,自动获取生成的主键...

    数据表设计时,一般都会有一个主键(Key)(自己指定),有时也可以使用联合主键: 有许多数据库提供了隐藏列为表中的每行记录分配一个唯一键值(如:rowid): 当我们没有指定哪一列作为主键key时,数 ...

  8. Python之路【第二篇】:Python基础(一)

    Python之路[第二篇]:Python基础(一) 入门知识拾遗 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 1 2 3 if 1==1:     name ...

  9. FPGA通信第二篇--UDP

    FPGA通信第二篇–UDP 本文通过对以太网通信中的UDP传输协议的理论学习,针对UDP实际应用中的丢包问题,提出一种人为的重发机制完成UDP稳定可靠的传输,并通过实验进行了验证. 1 以太网简介 以 ...

最新文章

  1. 解决虚拟机时间引起的奇怪问题
  2. (一)Eureka搭建服务注册中心
  3. PHP使用redis防止大并发下二次写入
  4. Python安装pycryptodome密码库
  5. java 设置session超时_Java设置session超时(失效)的时间
  6. 四种JSON解析工具--(json-libJacksonGsonFastJson)
  7. Mysql 常用命令
  8. spring mvc数据绑定与表单标签库
  9. YAML文件格式详解
  10. 软件著作权在开发完成时就自动享有了还有必要申请软件著作权登记么?
  11. 办公室计算机打印机共享,办公室小技巧:如何设置共享打印机
  12. 【整理】详解嵌入式片上资源之SDRAM内存
  13. 菜鸡帆并不算长の编程之旅回顾
  14. 【在线电子书转换】云展网教程 | 如何设置电子书的翻页速度?
  15. Java学习day096 并发(六)(线程安全的集合:高效的映射、集和队列、映射条目的原子更新、对并发散列映射的批操作、并发集视图、写数组的拷贝、并行数组算法、较早的线程安全集合)
  16. [转]浅析360的危害 我为什么推荐卸载360
  17. bmob php支付,个人开发者也能盈利!Bmob支付SDK使用实例
  18. 十本Android开发学习书籍下载链接
  19. Python paromiko每日生活学习感悟(第一次写,紧张hahaha)
  20. 2021年秋招面经分享·乐鑫【数字IC设计工程师】

热门文章

  1. java反编译器JAD.exe的使用
  2. .net实现URL重写
  3. 基于 HTML5 WebGL 的 3D 智慧隧道漫游巡检
  4. ThinkPHP5框架接入阿里云短信最新版(原大鱼)的方法
  5. asp.net 的web.config文件编写
  6. 公众号和小程序可以同名了 名称支持同主体复用
  7. 内存映射与DMA笔记
  8. senchaTouch 给组件传参的两种方式
  9. 数据库要不要放在docker
  10. 微信小程序,格式化千分位并保留两位小数