我有一个在 WildFly 服务器上运行的 Java EE 应用程序。持久化单元中的配置如下:
<persistence-unit name="default" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:/jboss/datasources/templateDS</jta-data-source>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<validation-mode>AUTO</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="use_sql_comments" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<!-- <property name="hibernate.cache.region.factory_class" vvalue="org.hibernate.transaction.CMTTransactionFactory"/>-->
<!-- <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.JndiInfinispanRegionFactory" />-->
<property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/container/hibernate" />
<!-- <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>-->
<property name="hibernate.generate_statistics" value="false" />
<!-- none | validate | update | create | create-drop -->
<property name="hibernate.hbm2ddl.auto" value="none" />
</properties>
</persistence-unit>
我有一些业务逻辑,用于向用户发送 Firebase 推送通知,作为一种有针对性的通信形式。用户基数相当大(> 10k),因此我们决定以 10 个为一组对消息收件人进行分页和批处理,以确保不存在内存问题。我有一个名为 MessageRecipient 的实体,它管理接收消息的用户。它有一个列来管理状态,当逻辑运行时,我们希望将每条已发送消息的状态从“未发送”更新为“已发送”或“失败”。以下是我在方法中运行的业务逻辑:
private void sendTargetedMessages(CsvFile dueFile) {
LOGGER.debug("in send targeted messages");
String filename = dueFile.getFilename();
String batchRef = filename.substring(0, filename.indexOf('.'));
// Calculate number of recipients.
int numberOfRecipients = crudService.findAllByColumn(MessageRecipient.class, batchRef, "batchRef").size();
int pageNumber = 0;
int pageSize = 10; //TODO: Change this to config entry
Integer num_sent = 0;
// Calculate number of pages. Use calculated number of pages to run the logic in a do while loop that increments
do {
List<MessageRecipient> recipients = crudService.findAllByColumn(MessageRecipient.class, batchRef, "batchRef", new Paging(pageNumber, pageSize));
// Execute the logic
if (recipients != null) {
// send targeted messages
User u;
for (MessageRecipient r : recipients) {
u = null;
if (RecipientState.UNSENT.equals(r.getState())) {
if (UserReferenceType.CVS_REF.equals(dueFile.getUserReferenceType())) {
u = userRepository.findUserByCvsRef(r.getReference(), Status.ACTIVE);
} else {
try {
u = userRepository.findUserByUserId(Long.parseLong(r.getReference()), Status.ACTIVE);
} catch (NumberFormatException e) {
r.setState(RecipientState.FAILED);
LOGGER.error("Reference cannot be converted to long.", e);
}
}
if (u != null) {
pushNotificationService.sendTargetedCommunication(u, dueFile.getCommId());
r.setState(RecipientState.SENT);
num_sent++;
}
//crudService.merge(r);
entityManager.merge(r);
entityManager.flush();
}
}
} else {
LOGGER.error("No recipients found for targeted communication.");
}
// Increment page number
pageNumber++;
} while (pageNumber <= (calculateNumberOfPages(numberOfRecipients, pageSize) - 1));
// Send email report once done
if (!StringUtils.isBlank(dueFile.getReportEmails())) {
String[] reportEmails = dueFile.getReportEmails().split(",");
List<String> reportEmailsList = Arrays.asList(reportEmails);
messagingReportService.sendEmailReport(reportEmailsList, batchRef, numberOfRecipients, num_sent, dueFile.getBucketName());
}
}
我调用entityManager merge() 和flush() 来尝试在发送推送通知后更新每个MessageRecipient 记录的状态,但状态在我的数据库(MySQL 数据库)中没有更新。我在应用程序中打开了 SQL 语句日志记录,并且看到 Hibernate 执行更新 SQL 语句,尽管我的数据库中没有更新。我该如何解决这个问题?
11:04:54,017 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) Hibernate:
11:04:54,018 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) update
11:04:54,018 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) message_recipient
11:04:54,019 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) set
11:04:54,019 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) last_updated=?,
11:04:54,019 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) batch_ref=?,
11:04:54,020 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) reference=?,
11:04:54,020 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) state=?
11:04:54,021 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) where
11:04:54,021 INFO [stdout] (EE-ManagedScheduledExecutorService-default-Thread-1) id=?
最初我只是调用
entityManager.merge(T entity)
,Hibernate 在尝试更新实体时没有生成更新 SQL 语句,但我添加了 entityManager.flush()
,现在我在日志中看到它。但是,我的问题是数据库也没有更新。
您正在使用二级缓存,可能是缓存尚未刷新事务,请尝试读取应用程序中的更改(如果您尝试读取时存在更改),没问题,它按预期工作,那么这意味着它的缓存未刷新还没有到 DB。
另一件事是确保您使用 EJB 和 @TransactionManagement(TransactionManagementType.CONTAINER) 在容器管理的 TX 范围内进行操作