子表行的休眠批处理
Posted
技术标签:
【中文标题】子表行的休眠批处理【英文标题】:Hibernate Batch processing for child table rows 【发布时间】:2018-09-29 13:52:08 【问题描述】:我在此链接Hibernate Batch insert 中尝试了批量插入的解决方案,但仍然无法正常工作。以下是相关代码供您参考。 我只上传了一个包含 100 行试算表的试算表文件。所以一个试算表是一个包含 100 个试算表行的列表,我需要批量插入这 100 行数据。 这是一个 REST API,因为它是双向关系,所以我使用 JSON 托管引用。
下面代码的结果是在试算表中插入了 6 行,而在试算表行表中插入了 100 行,仅针对最后一个创建的试算表 id,其余 id 没有数据插入到试算表行表中.
你能指出我哪里错了吗?
***TRIAL_BALANCE Entity***
@Entity
@Table(name="TRIAL_BALANCE")
public class TrialBalance
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ID")
private int id;
@OneToMany(mappedBy="trialBalance", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JsonManagedReference
private List<TrialBalanceRow> trialBalanceRows;
public void addTrialBalanceRows(List<TrialBalanceRow> tbRows)
if ( trialBalanceRows == null )
trialBalanceRows = new ArrayList<TrialBalanceRow>();
for ( TrialBalanceRow tb : tbRows )
trialBalanceRows.add(tb);
tb.setTrialBalance(this);
***TRIAL_BALANCE_ROW Entity***
@Entity
@Table(name="TRIAL_BALANCE_ROW")
public class TrialBalanceRow
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ID")
private int id;
@JsonBackReference
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="TRIAL_BALANCE_ID")
private TrialBalance trialBalance;
***TrialBalanceDOAImpl.java file***
public void addTrialBalance(TrialBalance trialBalance)
try
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<1200; i++ )
session.save(trialBalance);
if( i % 50 == 0 ) // Same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
tx.commit();
session.close();
catch (HibernateException e)
e.printStackTrace();
throw new DataNotSavedException();
休眠属性
hibernate.dialect = org.hibernate.dialect.mysqlDialect
hibernate.show_sql = true
hibernate.format_sql = false
spring.jpa.properties.hibernate.jdbc.time_zone = UTC
spring.jpa.properties.hibernate.jdbc.batch_size = 50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
spring.jpa.properties.hibernate.id.new_generator_mappings = false
休眠配置
private Properties hibernateProperties()
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.jdbc.time_zone",
environment.getRequiredProperty("spring.jpa.properties.hibernate.jdbc.time_zone"));
properties.put("hibernate.jdbc.batch_size",
environment.getRequiredProperty("spring.jpa.properties.hibernate.jdbc.batch_size"));
properties.put("hibernate.order_inserts",
environment.getRequiredProperty("spring.jpa.properties.hibernate.order_inserts"));
properties.put("hibernate.order_updates",
environment.getRequiredProperty("spring.jpa.properties.hibernate.order_updates"));
properties.put("hibernate.jdbc.batch_versioned_data",
environment.getRequiredProperty("spring.jpa.properties.hibernate.jdbc.batch_versioned_data"));
properties.put("hibernate.id.new_generator_mappings",
environment.getRequiredProperty("spring.jpa.properties.hibernate.id.new_generator_mappings"));
return properties;
日志
2018-07-12 16:28:25 TRACE AbstractEntityPersister:3142 - 更新实体:[in.greenstack.ikon.entity.TrialBalanceRow#107399] 2018-07-12 16:28:25 DEBUG AbstractBatchImpl:129 - 重用批处理语句 2018-07-12 16:28:25 调试 SQL:92 - 更新 TRIAL_BALANCE_ROW 设置 ACCOUNT_CODE=?, ACCOUNT_NAME=?, CLOSING_BALANCE=?, GL_AMOUNT_CURR=?, GL_AMOUNT_PROP=?, GL_AMOUNT_REV=?, OPENING_BALANCE=?, REMARKS=?, TRANSACTION_CR=?, TRANSACTION_DR=?, TRIAL_BALANCE_ID=? ID =? 休眠:更新 TRIAL_BALANCE_ROW 设置 ACCOUNT_CODE=?, ACCOUNT_NAME=?, CLOSING_BALANCE=?, GL_AMOUNT_CURR=?, GL_AMOUNT_PROP=?, GL_AMOUNT_REV=?, OPENING_BALANCE=?, REMARKS=?, TRANSACTION_CR=?, TRANSACTION_DR=?, TRIAL_BALANCE_ID=? ID =? 2018-07-12 16:28:25 TRACE AbstractEntityPersister:2723 - 脱水实体:[in.greenstack.ikon.entity.TrialBalanceRow#107399] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数1 作为 [INTEGER] - [0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [2] 作为 [VARCHAR] - [POOJA ENTERPRISE] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [3] 作为 [DOUBLE] - [0.0] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [4] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [5] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [6] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [7] 作为 [DOUBLE] - [0.0] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [8] 作为 [VARCHAR] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [9] 作为 [DOUBLE] - [14000.0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [10] 作为 [DOUBLE] - [14000.0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [11] 作为 [INTEGER] - [361] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [12] 作为 [INTEGER] - [107399] 2018-07-12 16:28:25 TRACE AbstractEntityPersister:3142 - 更新实体:[in.greenstack.ikon.entity.TrialBalanceRow#107400] 2018-07-12 16:28:25 DEBUG AbstractBatchImpl:129 - 重用批处理语句 2018-07-12 16:28:25 调试 SQL:92 - 更新 TRIAL_BALANCE_ROW 设置 ACCOUNT_CODE=?, ACCOUNT_NAME=?, CLOSING_BALANCE=?, GL_AMOUNT_CURR=?, GL_AMOUNT_PROP=?, GL_AMOUNT_REV=?, OPENING_BALANCE=?, REMARKS=?, TRANSACTION_CR=?, TRANSACTION_DR=?, TRIAL_BALANCE_ID=? ID =? 休眠:更新 TRIAL_BALANCE_ROW 设置 ACCOUNT_CODE=?, ACCOUNT_NAME=?, CLOSING_BALANCE=?, GL_AMOUNT_CURR=?, GL_AMOUNT_PROP=?, GL_AMOUNT_REV=?, OPENING_BALANCE=?, REMARKS=?, TRANSACTION_CR=?, TRANSACTION_DR=?, TRIAL_BALANCE_ID=? ID =? 2018-07-12 16:28:25 TRACE AbstractEntityPersister:2723 - 脱水实体:[in.greenstack.ikon.entity.TrialBalanceRow#107400] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数1 作为 [INTEGER] - [0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [2] 作为 [VARCHAR] - [Poonam Pride Bunglows] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [3] 作为 [DOUBLE] - [0.0] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [4] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [5] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [6] 作为 [DOUBLE] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [7] 作为 [DOUBLE] - [3842.0] 2018-07-12 16:28:25 TRACE BasicBinder:53 - 绑定参数 [8] 作为 [VARCHAR] - [null] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [9] 作为 [DOUBLE] - [15467.0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [10] 作为 [DOUBLE] - [11625.0] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [11] 作为 [INTEGER] - [361] 2018-07-12 16:28:25 TRACE BasicBinder:65 - 绑定参数 [12] 作为 [INTEGER] - [107400] 2018-07-12 16:28:25 DEBUG BatchingBatch:384 - 执行批量大小:50
我正在使用带有 spring security 和 spring v5+ 的 Hibernate v5.2.17。
谢谢, 修行
【问题讨论】:
【参考方案1】:弄清楚发生了什么的最好方法是enable JDBC logging。
就您而言,尚不清楚您是否正在提交交易。您是否在服务中使用@Transactional
?
此外,您应该使用适当的日志记录框架,而不是 e.printStackTrace
。
【讨论】:
是的,我在服务上使用@Transactional 然后,使用日志,看看执行了哪些语句。 我现在看到批量插入正在完成,但是对于大约 1200 行数据来说它的速度很慢。还有什么我想念的吗。用一些有效的日志和配置更改更新了帖子。 我看到另一个问题,即父表有多个同一行的插入。因此,在上面的示例中,如果 DAO 中的 addTrialBalance() 方法具有用于 15 行数据且批量大小为 5 的 for() 循环,我看到在 TrialBalance(父)表中添加了 4 行,并且 TrialBalanceRows(子)表已输入数据仅适用于生成的最后一个父 ID。为什么会在父表中生成 4 个插入? 在我给你的那个资源中都有解释。只需阅读它,您就会了解 INSERT 批量排序的工作原理。【参考方案2】:对于以后需要参考的其他人来说,对我有用的解决方案是为批量插入编写自己的 SQL 查询,如下所示。我还删除了父实体中的 CASCADETYPE.ALL 功能。
@Override
public void addTrialBalance(TrialBalance trialBalance)
try
//Batch insertion code
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
final int batchSize = 50;
session.save(trialBalance);
session.doWork(new Work()
public void execute(Connection con) throws SQLException
PreparedStatement st = con.prepareStatement(""
+ "insert into TRIAL_BALANCE_ROW (ACCOUNT_CODE, ACCOUNT_NAME, ....,TRIAL_BALANCE_ID) "
+ "values (?, ?,...,?)");
List<TrialBalanceRow> tbRows = trialBalance.getTrialBalanceRows();
List<TrialBalanceRow> trialBalanceRows = new ArrayList<TrialBalanceRow>();
int count = 0;
for (TrialBalanceRow tb : tbRows)
trialBalanceRows.add(tb);
tb.setTrialBalance(trialBalance);
count++;
st.setString(1, tb.getAccountCode());
st.setString(2, tb.getAccountName());
st.setDouble(3, tb.getClosingBalance());
.
.
.
st.setInt(11, tb.getTrialBalance().getId());
System.out.println("Adding to batch .......");
st.addBatch();
if(count % batchSize == 0)
System.out.println("Executing Batch Size of : " + batchSize);
st.executeBatch();
st.executeBatch();
st.close();
);
session.refresh(trialBalance);
tx.commit();
session.close();
catch (HibernateException e)
e.printStackTrace();
throw new DataNotSavedException();
感谢 Vlad 提供的参考资料(尤其是 GENERATIONTYPE.AUTO 上的参考资料)和所有帮助,但即使使用 order_inserts 我也无法获得预期的结果。通过上述解决方案,我能够达到所需的性能。
【讨论】:
以上是关于子表行的休眠批处理的主要内容,如果未能解决你的问题,请参考以下文章