这是我JDBC的第一篇

http://blog.csdn.net/hon_3y/article/details/53535798


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);

JDBC第二篇--【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】的更多相关文章

  1. jdbc执行预处理,批处理,LOB字段处理,调用存储过程

    (1)jdbc执行预处理 PreparedStatment预备语句 eg:String sql="insert into user(id,name,birthday,money) value ...

  2. JDBC【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】

    1.PreparedStatement对象 PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单 Statement对象编译SQL语句时, ...

  3. 【HANA系列】【第六篇】SAP HANA XS使用JavaScript(JS)调用存储过程(Procedures)

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第六篇]SAP HANA XS ...

  4. 通过 jdbc 分析数据库中的表结构和主键外键

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

  5. Cassandra开发入门文档第二部分(timeuuid类型、复合主键、静态字段详解)

    timeuuid类型 timeuuid具有唯一索引和日期时间的综合特性,可以与日期和时间函数联合使用,常用的关联函数: dateOf() now() minTimeuuid() and maxTime ...

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

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

  7. EC笔记,第二部分:5.了解C++默默编写并调用哪些函数

    5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ...

  8. 【MySQL】selectKey获取insert后的自动主键

    <insert id="insert" parameterType="cc.mrbird.febs.energy.domain.ChatGroup"> ...

  9. linux-0.11分析:boot文件 setup.s 第二篇随笔

    boot文件 setup.s 第二篇随笔 参考 [github这个博主的][ https://github.com/sunym1993/flash-linux0.11-talk ] 中断获取光标的位置 ...

随机推荐

  1. 轻量级ORM框架 QX_Frame.Bantina(一、框架简介)

    轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...

  2. 浅谈.NET,C#三层架构

     三层架构 常见架构: 三层(经典) MVC MVVM MVP   开发中常见的23种设计模式: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种: ...

  3. 实现quartz定时器及quartz定时器原理介绍(转)

    一.核心概念 Quartz的原理不是很复杂,只要搞明白几个概念,然后知道如何去启动和关闭一个调度程序即可.1.Job表示一个工作,要执行的具体内容.此接口中只有一个方法void execute(Job ...

  4. 80C51 数码管动态显示0~7

    所使用的开发板 普中科技HC6800-ES V2.0 PC:win7 64位 编译软件: keil uversion2 烧写工具: 普中科技开发的PZ-ISP V1.82 烧写方式:热烧写 #incl ...

  5. 在 Docker 中使用 flannel - 每天5分钟玩转 Docker 容器技术(60)

    上一节我们安装和配置了 flannel,本节在 Docker 中使用 flannel. 配置 Docker 连接 flannel 编辑 host1 的 Docker 配置文件 /etc/systemd ...

  6. Python 使用期物处理并发

    抨击线程的往往是系统程序员,他们考虑的使用场景对一般的应用程序员来说,也许一生都不会遇到--应用程序员遇到的使用场景,99% 的情况下只需知道如何派生一堆独立的线程,然后用队列收集结果. 示例:网络下 ...

  7. java注释中使用注解@see

    缘起 在写java时,有时需要写注释,而为了更好的描述,需要引用和参考其他代码.为了让阅读者更好的体验,javadoc中支持链接跳转,这就需要用到注解@see. @see用法 注解@see可以在注释中 ...

  8. 扩展Python模块系列(四)----引用计数问题的处理

    承接上文,发现在使用Python C/C++ API扩展Python模块时,总要在各种各样的地方考虑到引用计数问题,稍不留神可能会导致扩展的模块存在内存泄漏.引用计数问题是C语言扩展Python模块最 ...

  9. python基础教程(十)

    魔法方法.属性 ------------------------ 准备工作 为了确保类是新型类,应该把 _metaclass_=type 入到你的模块的最开始. class NewType(Objec ...

  10. SQL Server内存

    背景 最近一个客户找到我说是所有的SQL Server 服务器的内存都被用光了,然后截图给我看了一台服务器的任务管理器.如图 这里要说明一下任务管理器不会完整的告诉真的内存或者CPU的使用情况,也就是 ...