JDBC第二篇--【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】
这是我JDBC的第一篇
http://blog.csdn.net/hon_3y/article/details/53535798
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);
JDBC第二篇--【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】的更多相关文章
- jdbc执行预处理,批处理,LOB字段处理,调用存储过程
		(1)jdbc执行预处理 PreparedStatment预备语句 eg:String sql="insert into user(id,name,birthday,money) value ... 
- JDBC【PreparedStatment、批处理、处理二进制、自动主键、调用存储过程、函数】
		1.PreparedStatement对象 PreparedStatement对象继承Statement对象,它比Statement对象更强大,使用起来更简单 Statement对象编译SQL语句时, ... 
- 【HANA系列】【第六篇】SAP HANA XS使用JavaScript(JS)调用存储过程(Procedures)
		公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第六篇]SAP HANA XS ... 
- 通过 jdbc 分析数据库中的表结构和主键外键
		文章转自:http://ivan4126.blog.163.com/blog/static/20949109220137753214811/ 在某项目中用到了 hibernate ,大家都知道 hib ... 
- Cassandra开发入门文档第二部分(timeuuid类型、复合主键、静态字段详解)
		timeuuid类型 timeuuid具有唯一索引和日期时间的综合特性,可以与日期和时间函数联合使用,常用的关联函数: dateOf() now() minTimeuuid() and maxTime ... 
- java核心技术第四篇之JDBC第二篇
		01.JDBC连接池_连接池的概念: 1).什么是连接池:对于多用户程序,为每个用户单独创建一个Connection,会使程序降低效率.这时我们可以创建一个"容器", 这个容器中, ... 
- EC笔记,第二部分:5.了解C++默默编写并调用哪些函数
		5.了解C++默默编写并调用哪些函数 1.C++空类 C++会为一个空类建立以下函数 (1).默认构造函数 (2).默认拷贝构造函数 (3).析构函数 (4).赋值运算符(如果成员包含引用类型或con ... 
- 【MySQL】selectKey获取insert后的自动主键
		<insert id="insert" parameterType="cc.mrbird.febs.energy.domain.ChatGroup"> ... 
- linux-0.11分析:boot文件 setup.s 第二篇随笔
		boot文件 setup.s 第二篇随笔 参考 [github这个博主的][ https://github.com/sunym1993/flash-linux0.11-talk ] 中断获取光标的位置 ... 
随机推荐
- 使用proxool连接池配置教程
			proxool连接池的优点: 1.透明度:透明地将连接池添加到现有的JDBC驱动程序. 2.开源:我们的许可证允许您灵活地将其用于商业和其他开源产品. 3.标准:符合J2SE API,使您有信心开发标 ... 
- Spring Web MVC(一)
			[toc] 概述 Spring的web框架围绕DispatcherServlet设计. DispatcherServlet的作用是将请求分发到不同的处理器. Spring的web框架包括可配置的处理器 ... 
- WebClient 调用api
			使用: /// <summary> /// 获取用户信息 /// </summary> /// <param name="code"></ ... 
- 【Shell Basic】source . 与 bash sh 的区别
			一.在命令行窗口执行shell脚本时,source .所执行的脚本中,变量的作用域在当前shell窗口期,而bash.sh在shell脚本执行完了就失效了. dream361@master:~$ ca ... 
- 【Centos7】 firewalld命令行
			使用命令行管理firewall之前,说明有关于防火墙的策略独立性:明确的策略,策略之间无关联. 比如mysql使用3306,firewall添加mysql服务但未添加3306,当查询3306端口状态会 ... 
- Virtualbox虚拟机Ubuntu共享文件夹设置 自动挂载
			1. 安装增强功能包(Guest Additions) 安装好Ubuntu 14.04 后,运行Ubuntu并登录.然后在VirtualBox的菜单里选择"设备(D)" -> ... 
- vue.js基础知识篇(5):过渡、Method和Vue实例方法
			第8章:过渡 1.CSS过渡 2.JavaScript过渡 3.渐进过渡 第9章:method Vue.js的事件一般通过v-on指令配置在HTML中,虽然也可以在js的代码中使用原生的addEven ... 
- selenium系列------元素定位套路
			selenium定位分为上三门,平三门,下三门, id,name,linktext上三门, class ,css,js平三门, xpath,tag名,复数定位(定位一组然后选index元素). 
- 重写equals就必须重写hashCode的原理分析
			因为最近在整理Java集合的源码, 所以今天再来谈谈这个古老的话题,因为后面讲HashMap会用到这个知识点, 所以重新梳理下. 如果不被重写(原生Object)的hashCode和equals是什么 ... 
- Info模式下的隐形杀手(SpringMVC同时使用<mvc:resources.../>和FormattingConversionServiceFactoryBean时出现的问题)
			天气一天比一天变的凉快了,而我一天天踩的坑更加贱了,首先在北京向各位问好,也给身边献身教育事业的亲朋好友们补上一句节日快乐! 今天早上手贱把项目误删了,不得不去SVN上去乞求了.我个人习惯项目运行的时 ... 
