java中PreparedStatement与Statement相比具有啥优势?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中PreparedStatement与Statement相比具有啥优势?相关的知识,希望对你有一定的参考价值。

1、用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次2、PreparedStatement尽最大可能提高性能。PreparedStatement是预编译语句;预编译语句有可能被重复调用,语句在被编译器编译后的执行代码被缓存下来,下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。3、极大地提高了安全性,可以有效的避免SQL注入。 参考技术A PreparedStatement与Statement相比更安全,做相同类型的sql语言速度要快。
而且我觉得PreparedStatement好像书写起来也比较便捷,因为……=?在具体操作中比=……
操作起来要明了些 尤其是报错等时候。因为sql语言当做一个String,错了eclipse也不报错的嘛
越简短越好。我最近刚好用的很多,这是我的体会,希望对你有帮助
参考技术B 在JDBC应用中,如果你是稍有水平开发者,在任何时候都不要用Statement,PreparedStatement不管在安全性,效率性,维护性都比statement好很多 参考技术C PreparedStatement 预编译,一次编译,到处执行,效率高,并且参数可以使用占位符如(?,:test),安全些. 参考技术D 2.预编译PreparedStatement 使用范围:当执行相似sql语句的次数比较多(例如用户登陆,对表频繁操作..)语句一样,只是具体的值不一样,被称为动态SQL优点:语句只编译一次,减少编译次数。提高了安全性(阻止了SQL注入)缺点: 执行非相似SQL语句时,速度较慢。原理:相似SQL只编译一次,减少编译次数名词解释:SQL注入:select * from user where username="张三" and password="123" or 1=1;前面这条语句红色部分就是利用sql注入,使得这条词句使终都会返回一条记录,从而降低了安全性。事例执行过程: public void exec2(Connection conn) try Long beginTime = System.currentTimeMillis(); conn.setAutoCommit(false);//手动提交 PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)"); for(int i=0;i<10000;i++) pst.setInt(1, i); pst.execute(); conn.commit(); Long endTime = System.currentTimeMillis(); System.out.println("Pst用时:"+(endTime-beginTime)+"秒");//计算时间 pst.close(); conn.close(); catch (SQLException e) e.printStackTrace(); 执行时间:Pst用时:14秒 3.使用PreparedStatement + 批处理使用范围:一次需要更新数据库表多条记录优点:减少和SQL引擎交互的次数,再次提高效率,相似语句只编译一次,减少编译次数。提高了安全性(阻止了SQL注入)缺点:原理:批处理: 减少和SQL引擎交互的次数,一次传递给SQL引擎多条SQL。名词解释:PL/SQL引擎:在oracle中执行pl/sql代码的引擎,在执行中发现标准的sql会交给sql引擎进行处理。SQL引擎:执行标准sql的引擎。事例执行过程:public void exec3(Connection conn) try conn.setAutoCommit(false); Long beginTime = System.currentTimeMillis(); PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)"); for(int i=1;i<=10000;i++) pst.setInt(1, i); pst.addBatch();//加入批处理,进行打包 if(i%1000==0)//可以设置不同的大小;如50,100,500,1000等等 pst.executeBatch(); conn.commit(); pst.clearBatch(); pst.executeBatch(); Long endTime = System.currentTimeMillis(); System.out.println("pst+batch用时:"+(endTime-beginTime)+"毫秒"); pst.close(); conn.close(); catch (SQLException e) // TODO Auto-generated catch block e.printStackTrace(); 执行时间:pst+batch用时:485毫秒

线程中的 PreparedStatement (java)

【中文标题】线程中的 PreparedStatement (java)【英文标题】:PreparedStatement in Threads (java) 【发布时间】:2022-01-07 02:53:58 【问题描述】:

我正在编写一个将线程插入数据库的程序。 示例

public static void save(String name)

    try(PreparedStatement preparedStatement = ...insert...)
    
        preparedStatement.setString(1, name);
        preparedStatement.executeUpdate();
        preparedStatement.close();
     catch (...)
    

问题:会不会是同时执行insert到表的线程时,一个线程会使用(preparedStatement.executeUpdate())另一个线程的preparedStatement?

【问题讨论】:

【参考方案1】:

当然。您不应该这样做 - 每个线程都需要有自己的数据库连接(因此意味着它必然也有自己的 PreparedStatement)。

更好的是 - 不要这样做。你只是让事情变得混乱和缓慢,这是双输的。您的计划完全没有任何好处。如果同时从 2 个线程插入,数据库不会神奇地更快地完成这项工作。

结论很简单:在将大量数据插入同一个表时,线程是一个非常糟糕的主意,所以不要这样做!

但我真的很想加快我的插入速度!

我的数据收集速度很慢

IF(大如果!!)收集数据以进行插入比数据库可以为您插入记录要慢,并且数据收集工作非常适合多-threading,然后让线程收集数据,但让这些线程将对象放入队列,并有一个单独的“数据库插入器”线程(甚至与数据库有连接的唯一线程)将对象从该队列中拉出运行 INSERT。

如果您可以快速收集数据,或者源不适合多线程,这只会使您的代码更长、更难理解、更难测试和更慢。一点意义都没有。

有用的工具:LinkedBlockingQueue - 它的一个实例是所有线程都拥有的一个共享数据。您的数据收集器线程将对象扔到此队列中,而您的单个 db 插入线程从中获取对象。

一般插入速度建议 1:捆绑

数据库在事务中工作。如果您启用了自动提交模式(并且连接以这种模式启动),那不是“无事务”。这仅仅是(因此得名):数据库在每次事务后提交。您不能在适当的数据库中执行“非事务性”。 commit() 很重(需要很长时间来处理),但过长的事务也是如此(在提交之前在单个事务中执行数千件事)。因此,你得到了金发姑娘的原则:你想运行大约 500 次左右的插入,然后提交。

请注意,这有一个缺点:如果在此过程的中途发生错误,则说明有些记录已提交,有些尚未提交。请记住这一点 - 您的流程需要是幂等的,或者这可能是不可接受的,并且您需要 使其 幂等(例如,通过列出“插入会话”ID 的列,因此您如果操作无法正确完成,可以将它们全部删除) - 如果您的数据库同时被其他东西使用,您还需要更多复杂性(某种标志或过滤器,以便其他同时代码不考虑任何已提交, 插入记录直到整个批次被完全添加)。

相关方法:

con.setAutoCommit(false); con.commit() 这个一般结构:
try (PreparedStatement ps = con.prepare.......) 
  int inserted = 0;
  while (!allGenerationDone) 
    Data d = queue.take();
    ps.setString(1, d.getName());
    ps.setDate(2, d.getBirthDate());
    // set the other stuff
    ps.execute();
    if (inserted++ % 500 == 0) con.commit();
  

con.commit();

一般插入速度建议 2:批量

大多数数据库引擎都有用于批量插入的特殊命令。从数据库引擎的角度来看,在进行批量插入时,各种清理和维护任务需要大量时间,甚至可能不是必需的,或者可以组合起来以节省大量时间。具体来说,检查约束(尤其是参考约束)和构建索引占用了处理INSERT 的大部分时间,这些事情可以完全跳过,也可以通过在最后一次批量执行来大大加快.

执行此操作的方式高度依赖于底层数据库。例如,在 postgres 中,您可以关闭约束检查并关闭索引构建,然后运行插入,然后重新启用。您甚至可以选择完全忽略约束检查(这意味着,如果您的代码混乱,您的数据库可能处于无效状态,但如果速度比安全更重要,这可能是正确的方法)。如果在最后完成,索引构建会相当快。

其他数据库一般都有类似的策略。或者,有一些命令将它们组合在一起,通常称为COPY(而不是INSERT)。检查您的数据库引擎的文档。

阅读this SO question 以获取有关COPYINSERT 比较的一些信息和基准。并使用网络搜索引擎搜索例如mysql bulk insert.

【讨论】:

感谢您的详细解答。我同意。我尝试使用单个线程在最后插入(来自“while”队列的 PrepareStatement),但在 SQLException 之后丢失了数据。我没有深入研究并进行了当前的实施。我将从队列中的一个线程中插入。谢谢!

以上是关于java中PreparedStatement与Statement相比具有啥优势?的主要内容,如果未能解决你的问题,请参考以下文章

java中PreparedStatement与Statement相比具有啥优势?

Java操作数据库(一,SQL注入与PreparedStatement)

Java、PreparedStatement、TransactSQL (MS SQL)、最后插入 ID

PreparedStatement 与 Statement

线程中的 PreparedStatement (java)

Java中PreparedStatement和Statement的用法区别