我想在EntityManager关闭之前执行任务(例如,在关闭AS或取消部署应用程序时),并寻找一个Hook或Listener或类似的东西。
实际的问题:我想用我的应用程序在数据库中保存很多微小的数据。为了减轻数据库的负载,我将数据缓存在一个List中,并希望以给定的时间间隔保存所有数据。
到目前为止,这种方法效果很好,但是如果AS关闭,数据将丢失。这就是为什么我要在EntityManager关闭之前保存数据的原因。
到目前为止,我已经尝试过:我尝试使用@PreDestroy批注在bean被销毁之前保存数据。不幸的是,EntityManager的使用无法正常工作,正如我稍后阅读的那样,PreDestroy方法中不允许使用。
@Singleton
@Startup
@DependsOn(value = "StatisticRepository")
public class StatisticService {
private static final Logger LOG = Logger.getLogger(StatisticService.class.getName());
@EJB
private StatisticRepository repository;
private List<Statistic> stats = new ArrayList<>();
@PreDestroy
public void destroy() {
LOG.log(Level.INFO, "Saving before destroying Service.");
for (Statistic stat : stats) {
// ---> EntityManager in Repository already destroyed
repository.create(stat);
}
stats.clear();
}
...
}
。
@Singleton
@Startup
public class StatisticRepository extends BaseRepository<Statistic>{
public StatisticRepository() {
super(Statistic.class);
}
@PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
...
}
。
@MappedSuperclass
public abstract class BaseRepository<T extends Serializable> {
protected abstract EntityManager getEntityManager();
private final Class<T> entityClass;
public BaseRepository(Class<T> entityClass) {
this.entityClass = entityClass;
}
public T create(T entity) {
getEntityManager().persist(entity);
getEntityManager().flush();
return this.edit(entity);
}
...
}
我得到这个例外
信息:在销毁服务之前保存统计信息。 警告:RAR5114:分配连接时出错:[{PoolInfo :(名称= Java:应用程序/池),((ApplicationName =应用名称))}:池{PoolInfo :(名称= Java:应用程序/池)没有池元数据对象,(applicationName = AppName)}链接。重新部署应用程序。] Warnung:本地异常堆栈: 异常[EclipseLink-4002](Eclipse Persistence Services-2.5.0.v20130507-3faac2b):org.eclipse.persistence.exceptions.DatabaseException 内部异常:java.sql.SQLException:{PoolInfo :(名称= java:应用程序/池),(applicationName = AppName)}:它不是具有池{PoolInfo :(名称= java:应用程序/池)的池元数据对象),((applicationName = AppName)}链接。重新部署应用程序。 错误代码:0 ...
似乎池(已在应用程序范围内)已取消部署。
完整的堆栈跟踪:
这里
我在glassfish-resources.xml上创建我的JNDI资源和连接池。因此,它不是应用程序服务器范围的资源。也许这是重现错误的关键?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<!-- MySQL -->
<jdbc-connection-pool allow-non-component-callers="false"
associate-with-thread="false"
connection-creation-retry-attempts="0"
connection-creation-retry-interval-in-seconds="10"
connection-leak-reclaim="false"
connection-leak-timeout-in-seconds="0"
connection-validation-method="auto-commit"
datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
fail-all-connections="false"
idle-timeout-in-seconds="170"
is-connection-validation-required="true"
is-isolation-level-guaranteed="true"
transaction-isolation-level="repeatable-read"
lazy-connection-association="false"
lazy-connection-enlistment="false"
match-connections="false"
max-connection-usage-count="0"
max-pool-size="100"
max-wait-time-in-millis="60000"
name="java:app/mysql_app_appPool"
non-transactional-connections="false"
ping="true"
pool-resize-quantity="2"
pooling="true"
res-type="javax.sql.DataSource"
statement-cache-size="0"
statement-leak-reclaim="false"
statement-leak-timeout-in-seconds="0"
statement-timeout-in-seconds="0"
steady-pool-size="20"
validate-atmost-once-period-in-seconds="0"
wrap-jdbc-objects="true">
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</jdbc-connection-pool>
<jdbc-resource enabled="true" jndi-name="java:app/jdbc/app" object-type="user" pool-name="java:app/mysql_app_appPool"/>
。
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- Persistence Unit for MySQL -->
<persistence-unit name="com.app.web_app-webapp_war_1.0-SNAPSHOTPU" transaction-type="JTA">
<jta-data-source>java:app/jdbc/app</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
<property name="javax.persistence.schema-generation.create-source" value="metadata-then-script"/>
<property name="javax.persistence.schema-generation.drop-source" value="metadata"/>
<property name="javax.persistence.schema-generation-target" value="database"/>
</properties>
</persistence-unit>
</persistence>
问题:您总体上对这种机制有何看法?JPA可以自己更好地处理缓存,这样有意义吗?是否有监听器或挂钩?
eclipselink上有很多缓存选项。在这里看看。
另外,为了获得真实的生活表现,我强烈建议使用Infinspan。在这里看看。
如果您的用例真的很简单,那么用@Singleton
注释的ejb bean@Startup
应该可以解决问题。像这样:
@Singleton
@Startup
public class StartupShutdownBean {
@PostConstruct
private void startup() {
// your startup code here
}
@PreDestroy
private void shutdown() {
// your shutdown code here
}
}
EntityManager
在此bean上注入,您应该没有任何问题。最有可能的是,您不能在bean中使用实体管理器,因为在执行“缓存更新”之前,事务已结束。
编辑:
似乎在您的@PreDestroy
呼叫之前,AS已删除了应用程序配置的资源,因此preserveAppScopedResources=true
,应在asadmin deploy或redeploy命令中使用该参数,以使池在这些操作期间保持活动状态。
一些文档在这里。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句