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

小编 2026-06-27 阅读:893 评论:0
1.PreparedStatement对象PreparedStatement对象继承Statem...

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

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

更多的文章可往:文章的目录导航
版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

上一篇:JAVA基础3(异常) 下一篇:Java this keyword
热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表