我目前正面临众所周知和常见的Hibernate插入批处理问题.
我需要保存500万行的批次.我首先尝试使用更轻的有效载荷.由于我必须只插入两种类型的实体(首先是所有类型A的记录,然后是所有类型B的记录,都指向公共类型C ManyToOne父级),我想从JDBC批量插入中获取最大优势.
我已经阅读了很多文档,但我没有尝试过.
AUTO_INCREMENTID,我用一个技巧设置了ID:SELECT MAX(ID) FROM ENTITIES每次都增加.hibernate.jdbc.batch_size与我的应用程序的批量大小一致,所以我在LocalSessionFactoryBean(Spring ORM集成)中设置它这是我的实体
共同的父实体.这将首先插入到单个事务中.我不关心这里的自动增量列.每批作业只有一个记录
@Entity
@Table(...)
@SequenceGenerator(...)
public class Deal
{
@Id
@Column(
name = "DEAL_ID",
nullable = false)
@GeneratedValue(
strategy = GenerationType.AUTO)
protected Long id;
................
}
Run Code Online (Sandbox Code Playgroud)
其中一个孩子(假设每批2.5M记录)
@Entity
@Table(
name = "TA_LOANS")
public class Loan
{
@Id
@Column(
name = "LOAN_ID",
nullable = false)
protected Long id;
@ManyToOne(
optional = false, …Run Code Online (Sandbox Code Playgroud) 我试图使用Hibernate(JPA)在5秒内在MYSQL表中插入100,000行.我已经尝试过hibernate提供的每一个技巧,但仍然不能超过35秒.
第一次优化:我开始使用IDENTITY序列生成器,这导致插入60秒.我后来放弃了序列生成器并开始@Id自己通过阅读MAX(id)和使用AtomicInteger.incrementAndGet()自己分配字段来分配字段.这将插入时间减少到35秒.
第二次优化:我通过添加启用了批量插入
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.jdbc.batch_versioned_data">true</prop>
到配置.我很震惊地发现批量插入绝对没有减少插入时间.现在还有35秒!
现在,我正在考虑尝试使用多个线程插入.任何人有任何指针?我应该选择MongoDB吗?
下面是我的配置:1.Hibernate配置`
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.progresssoft.manishkr" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.jdbc.batch_versioned_data">true</prop>
</props>
</property>
</bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
id="dataSource">
<property name="driverClassName" value="${database.driver}"></property>
<property name="url" value="${database.url}"></property>
<property name="username" value="${database.username}"></property>
<property name="password" value="${database.password}"></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" …Run Code Online (Sandbox Code Playgroud) 我想在hibernate Hql中的同一个查询中执行多个更新语句.如下:
hql = " update Table1 set prob1=null where id=:id1; "
+ " delete from Table2 where id =:id2 ";
...
query.executeUpdate();
Run Code Online (Sandbox Code Playgroud)
在同一个executeUpdate调用中,我想更新Table1中的记录并从Table2中删除记录.
那可能吗?
环境
休眠4.2
ojdbc6 - Oracle 11.2.0.3.0 JDBC 4.0
Oracle 数据库 11g
问题
我们遵循许多建议,按照以下方式配置 Hibernate 批处理:
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>
Run Code Online (Sandbox Code Playgroud)
我们检查了日志,发现生成的 SQL 语句是批处理的。但是,如果两个事务同时修改相同版本的实体行,Hibernate 将成功提交这两个事务,从而导致最后提交的事务中的冲突更新丢失(非冲突数据保存在两个事务中,因此最后一个事务离开数据库)处于不一致的状态)。
令人惊讶的是,关于这种行为的文档很少。Hibernate官方文档说:
hibernate.jdbc.batch_versioned_data
如果您的 JDBC 驱动程序从executeBatch() 返回正确的行计数,请将此属性设置为 true。打开此选项通常是安全的。然后,Hibernate 将使用批处理 DML 来自动控制版本数据。默认为 false。
平时安全吗?我们几乎将其投入生产,然后才注意到整个版本控制已被破坏。
我们在谷歌上搜索了五年前发布的一篇博客,描述了这种奇怪的现象;显然 Hibernate 已经很长时间没有在这方面做任何事情了。
Hibernate 这样做有什么原因吗?它从 jdbc 驱动程序获取的信息是更新的行数未知,为什么它不抛出异常来指示它,而是留下版本检查已成功通过的印象?
有人可以解释我如何
hibernate.jdbc.batch_size=1000
Run Code Online (Sandbox Code Playgroud)
和
if (i % 100 == 0 && i>0) {
session.flush();
session.clear();
}
Run Code Online (Sandbox Code Playgroud)
一起工作?...
我正在用java编写一个函数,用hibernate生成并保存一个唯一的代码,然后在get请求中发送它,我将不得不在一次调用中执行此操作30,000次。
即使我无法将 HttpRequest 与 hibernate insert 分开,多线程会帮助我加快速度吗?
hibernate ×6
java ×5
mysql ×4
batch-insert ×2
hql ×1
httprequest ×1
jdbc ×1
jpa ×1
ojdbc ×1
oracle ×1