Промежуточное время для промывки с помощью Hibernate
Я использую Hibernate 5.2.8. Окончательная версия, и у нас есть требование, чтобы мы считывали миллионы данных из базы данных и обновляли данные с помощью некоторой бизнес-логики, поскольку моя база данных огромна, я хочу зафиксировать данные после того, как мой размер пакета достигнут, поэтому у меня есть написанный ниже код
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
Query<Object> query = session.createQuery(SQL, Object.class);
ScrollableResults scrollableResults = query.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
while (scrollableResults.next())
{
Object object = (Object) scrollableResults.get(0);
process(object)
session.update(object);
if (++count % batchSizeDeclare== 0)
{
session.flush();
session.clear();
LOGGER.info("Updated batch records");
}
}
session.getTransaction().commit();
LOGGER.info("commited in Hibernate ");
}
Ниже мой hibernate.cfg.xml
файл
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.url">jdbc:sqlserver://com;database=DEV</property>
<property name="connection.username">user</property>
<property name="connection.password">pass</property>
<property name="hibernate.default_schema">schema</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">5</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.SQLServer2012Dialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<!-- <property name="show_sql">true</property> -->
<!-- <property name="format_sql">true</property> -->
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>
<!-- org.hibernate.HibernateException: No CurrentSessionContext configured! -->
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<mapping class="com.beans.Object" />
</session-factory>
</hibernate-configuration>
Ниже мой Object.java
public class Object implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false, unique = true, updatable = false)
private int id;
private String filePath;
private String fileName;
private String mimeType;
private double fileSize;
// removed getters and setters
}
Как только мой код достигает session.flush(), он ничего не делает даже после ожидания в течение 30 минут. Это правильный способ пакетной фиксации? Как сделать пакетное обновление?
1 ответ
Как только мой код достиг session.flush, он ничего не делает даже после ожидания в течение 30 минут.
Напротив! База данных делает слишком много. Просто вы не видите никакого прогресса, потому что база данных изо всех сил пытается справиться с огромным количеством работы, которую вы представили.
Это правильный способ пакетной фиксации?
Краткий ответ - нет.
Как я объяснил в статье 14 высокопроизводительных советов по сохранению Java, вам не нужно извлекать миллионы строк из БД. У вас есть лучшие варианты:
- Вы можете выполнять обработку в базе данных, так что вы не платите цену за извлечение данных и их отправку по сети, а только за их обработку в Java.
- Если вы не можете обработать его в БД<, тогда вам нужно использовать пакетный процессор, который за раз получает только небольшие порции данных. Таким образом, вы можете даже распараллелить пакетную обработку, что должно сократить общее время обработки.
Единственный способ исправить это - изменить свой подход.