在EntityManager关闭之前执行任务

伊瑟

我想在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可以自己更好地处理缓存,这样有意义吗?是否有监听器或挂钩?

ra2085

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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在EntityManager关闭之前执行任务

来自分类Dev

如何确保在启动不同服务之前执行任务

来自分类Dev

在flask-sqlalchemy中插入,删除等之前执行任务

来自分类Dev

执行任务之前调用的Task#call()方法

来自分类Dev

在Python中执行任务的计时器-已关闭-

来自分类Dev

并行执行任务

来自分类Dev

定期执行任务

来自分类Dev

阻止Gradle Zip任务在执行任务之前下载依赖项

来自分类Dev

延迟然后执行任务

来自分类Dev

让异步等待并执行任务

来自分类Dev

依次执行任务序列

来自分类Dev

Gradle:执行任务失败

来自分类Dev

JBPM多次执行任务

来自分类Dev

执行任务后绑定?

来自分类Dev

用构建任务执行任务

来自分类Dev

创建任务列表,不执行任务

来自分类Dev

创建任务列表,不执行任务

来自分类Dev

从执行任务中创建任务

来自分类Dev

在Apache Server将请求转发到Tomcat之前如何执行任务?

来自分类Dev

如何在Ansible中执行任务之前强制处理程序运行?

来自分类Dev

如何在执行任务之前显示进度指示器?

来自分类Dev

在进行下一次迭代之前,如何使我的for循环完全执行任务?

来自分类Dev

如何在执行任务之前等待绑定获取其值

来自分类Dev

从php脚本中执行任务

来自分类Dev

gradle构建后执行任务

来自分类Dev

何时并行执行任务是过大的?

来自分类Dev

并行运行多个执行任务

来自分类Dev

Celerybeat计划执行任务多次?

来自分类Dev

并行执行任务“ n”次