在Java中,PreparedStatement如何处理以下查询

发布于 2024-09-19 07:35:03 字数 808 浏览 5 评论 0原文

我有一个如下所示的查询,想知道通过批处理PreparedStatement 会生成什么样的SQL。

INSERT INTO table1 (id, version, data)
  VALUES (?, ?, ?)
  ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data),
    table1.version = IF(table1.version > table2.version, table1.version, table2.version)

问题是,它会将其解析为批处理中每一行的整个 sql 字符串的副本,还是会执行以下操作:

INSERT INTO table1 (id, version, data)
  VALUES (a1, b1, c1), (a2, b2, c2), (a3, b3, c3), ...
  ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data),
    table1.version = IF(table1.version > table2.version, table1.version, table2.version)

如果不是,性能影响是什么,以及如何以这样的方式编写它:使用PreparedStatement 批处理许多这样的INSERT..UPDATE 语句而不导致性能损失?

I have a query like the following and was wondering what kind of SQL is produced by batching a PreparedStatement.

INSERT INTO table1 (id, version, data)
  VALUES (?, ?, ?)
  ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data),
    table1.version = IF(table1.version > table2.version, table1.version, table2.version)

The question is, will it resolve this to a copy of this whole sql string for each row in the batch or will it do something like:

INSERT INTO table1 (id, version, data)
  VALUES (a1, b1, c1), (a2, b2, c2), (a3, b3, c3), ...
  ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data),
    table1.version = IF(table1.version > table2.version, table1.version, table2.version)

If not, what is the performance implication and how do I write it in such a way that I can batch many of these INSERT..UPDATE statements using PreparedStatement without incurring a performance penalty?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

没有你我更好 2024-09-26 07:35:23

准备好的语句只是将您放入的位置值插入到重复语句中,然后不需要每次都进行解析。因此,您的第二种形式只需要 N * 3 个参数,并且不会为您提供准备好的语句的任何速度改进。对于重复语句,您需要使用 addTobatch。基本上你准备语句,(例如“UPDATE ...???”,然后一次添加3个参数,并一次执行批处理。

我曾经使用这样的东西作为实用程序来包装这个混乱的东西所以你就做类似的事情

  SQLBatchHandler h = new SQLBatchHandler(conn, "UPDATE ... WHERE ? ? ? ... ");
  h.addToBatch(x, y,z);
  h.addToBatch(x2,y2,z2);
  ...
  h.flush();



public class SQLBatchHandler {
    public static int           MAX_BATCH_SIZE  = 500;
    public String           query;
    private Connection      conn;
    private PreparedStatement   ps;
    private int             batch_ct;

    public SQLBatchHandler(Connection c, String query) throws SQLException
        {
        conn = c;
        this.query = query;
        ps = conn.prepareStatement(query);
    }

    /**
     * add this row to the batch and handle the commit if the batch size
     * exceeds {@link #MAX_BATCH_SIZE}
     * 
     * @param values row values
     * @throws SQLException
     */
    public void addToBatch(Object ... values) throws SQLException
    {
        int i = 0;
        for (Object value: values)
        {
            ps.setObject((++i), value);
        }
        add();
    }

    private void add() throws SQLException
    {
        ps.addBatch();
        if ((++batch_ct) > MAX_BATCH_SIZE)
        {
            ps.executeBatch();
            batch_ct = 0;
        }
    }

    /**
     * Commit any remaining objects and close.
     * 
     * @throws SQLException On statement close error.
     */
    public void flush() throws SQLException
    {
        if (batch_ct == 0) { return; }
        try
        {
            ps.executeBatch();
        }
        catch (SQLException e)
        {
            throw e;
        }
        finally
        {
            if (ps != null)
            {
                ps.close();
            }
        }
    }
}

A prepared statement just inserts the positional values you put in into a repeating statement which then doesn't need to be parsed each time. So your second form would just require N * 3 parameters and wouldn't give you any of the speed improvement of a prepared statement. For repeating statements you want to use addTobatch. Basically you prepare the statement, (e.g. "UPDATE ... ? ? ? " and then add 3 parameters at a time, and execute the batch all at once.

I used to use something like this as a utility to wrap the messiness of this. So you'd just do something like

  SQLBatchHandler h = new SQLBatchHandler(conn, "UPDATE ... WHERE ? ? ? ... ");
  h.addToBatch(x, y,z);
  h.addToBatch(x2,y2,z2);
  ...
  h.flush();



public class SQLBatchHandler {
    public static int           MAX_BATCH_SIZE  = 500;
    public String           query;
    private Connection      conn;
    private PreparedStatement   ps;
    private int             batch_ct;

    public SQLBatchHandler(Connection c, String query) throws SQLException
        {
        conn = c;
        this.query = query;
        ps = conn.prepareStatement(query);
    }

    /**
     * add this row to the batch and handle the commit if the batch size
     * exceeds {@link #MAX_BATCH_SIZE}
     * 
     * @param values row values
     * @throws SQLException
     */
    public void addToBatch(Object ... values) throws SQLException
    {
        int i = 0;
        for (Object value: values)
        {
            ps.setObject((++i), value);
        }
        add();
    }

    private void add() throws SQLException
    {
        ps.addBatch();
        if ((++batch_ct) > MAX_BATCH_SIZE)
        {
            ps.executeBatch();
            batch_ct = 0;
        }
    }

    /**
     * Commit any remaining objects and close.
     * 
     * @throws SQLException On statement close error.
     */
    public void flush() throws SQLException
    {
        if (batch_ct == 0) { return; }
        try
        {
            ps.executeBatch();
        }
        catch (SQLException e)
        {
            throw e;
        }
        finally
        {
            if (ps != null)
            {
                ps.close();
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文