如何制作将生成 SQL 以在一条语句中插入多个值的 HQL?

Posted

技术标签:

【中文标题】如何制作将生成 SQL 以在一条语句中插入多个值的 HQL?【英文标题】:how to make HQL that will generate SQL to insert multiple values in one statement? 【发布时间】:2013-07-25 14:12:06 【问题描述】:

我需要休眠来生成像这样INSERT INTO table_a (a_id, a_name) VALUES (5, 'a5'),(6, 'a6');这样的sql。

使用这样的 sql,您可以使用 1 条语句添加 2 行。我可以得到

a_id, a_name

------------------
5     a5
6     a6

在hibernate中,当你保存一组一对多关系时,hibernate会插入multiple insert statement。如果您使用 HQL 将 1000 行插入到 1 个表中,这将导致如下结果:

INSERT INTO scoring.table_a (`a_id`, `a_name`) VALUES (1, 'a');
INSERT INTO scoring.table_a (`a_id`, `a_name`) VALUES (2, 'a');
....
...
..
INSERT INTO scoring.table_a (`a_id`, `a_name`) VALUES (1000, 'a');

经过的时间是:

Executed 1,000 queries; elapsed time (seconds) - Total: 0.78, SQL query: 0.78, Building output: 0

当我使用相同的值进行测试时,使用 SQL INSERT INTO table_a (a_id, a_name) VALUES (5, 'a'),(6, 'a'),(),...,...,(1000, 'a'); 将导致这样的经过时间:

Query 1 of 1, Rows read: 0, Elapsed time (seconds) - Total: 0.02, SQL query: 0.02, Building output: 0

我的测试结果是,1000 个值(0.02 秒)的 1 个语句将比 1000 个插入语句快 39 倍,每个语句都有 1 个值(0.78 秒),就像休眠一样。那么有没有一种方法可以让 HQL 生成类似用于插入或更新的 SQL。或者这意味着我们必须重写休眠方言?

感谢任何提示

【问题讨论】:

【参考方案1】:

在 Hibernate 文档中有一个关于 batch processing 的非常好的章节。

设置属性

hibernate.jdbc.batch_size 20

然后使用此代码

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) 
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 )  //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    


tx.commit();
session.close();

根据您的需要从上面的代码中更改customer 对象。

【讨论】:

【参考方案2】:

HQL 仅支持 INSERT INTO ……… SELECT ……… ;没有机会写INSERT INTO ………VALUES,我的意思是在编写插入查询时,我们需要从其他表中选择值,我们不能手动插入自己的值。 (see documentation 和 this)

【讨论】:

【参考方案3】:

您可以将hibernate.jdbc.batch_size 属性设置为非零值。它将允许 Hibernate 使用批处理 INSERT。看看a official documentation。

以下代码是如何通过 Hibernate 使用 JDBC 批量插入的示例:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i < 10000; i++ ) 
    RecordA record = new RecordA(.....);
    session.save(record);
    if ( i % BATCH_SIZE == 0 )  // BATCH_SIZE is your choice, but equal to property
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    

tx.commit();
session.close();

这里也有讨论:Hibernate batch size confusion

【讨论】:

据我所知,batch_size 设置是一个内存优化问题,以最大限度地减少往返而不发生内存泄漏。 插入仍然在一个事务中的多个语句中。所以 batch_size 不是这里的解决方案。不过还是谢谢.. 如Hibernate batch size confusion 中所述,hibernate.jdbc.batch_size 允许使用 JDBC2 API 功能,该功能将 连续 INSERT 语句与 相同签名 (表& cols) 合并到一个具有多个 如果主键不是 GenerationType.Identity. 的语句中 是的,连续的 INSERT 语句单个 INSERT 语句不同。正如我之前在评论中所说,插入仍然在一个事务中的多个语句中

以上是关于如何制作将生成 SQL 以在一条语句中插入多个值的 HQL?的主要内容,如果未能解决你的问题,请参考以下文章

如何在一条 SQL 语句中组合两个不同的 SQL 查询?

Spring JDBC - 针对多个表的批量插入

SqlServer怎么获得生成的newid()的值

SQL查询以在一组语句中查找最大值[重复]

如何在一张图片上制作多个超级链接?

如何用SQL语句向一个表中插入多行记录