我正在使用EJB计时器但是在尝试在同一个项目中运行计时器和持久化实体时遇到了麻烦。在我的初始设置中,我只有定时器,这些按预期启动:
@Stateless
public class TimerHandler {
@Resource
protected TimerService mTimerService;
@PostConstruct
public void init() {
// could do cool stuff but choose not to
}
public Timer start(long aDuration) {
TimerConfig conf = new TimerConfig();
conf.setPersistent(false); // don't want the timer to be saved
return mTimerService.createSingleActionTimer(aDuration, conf);
}
@Timeout
public void timeOutAction(Timer aTimer) {
// does fancy stuff
System.out.println("So fancy :)");
}
}
让定时器运行时遇到了一些麻烦,但是我采用了强力方式并重新安装了Payara(Glassfish)。在此之后使用Timer很好。我可以这样开始并取消它:
@Stateful
public class MyClass {
@EJB
private TimerHandler mTimerHandler;
private Timer mTimer;
public void startTimer(int aDuration) {
mTimer = mTimerHandler.start(aDuration);
}
public void stopTimer() {
try {
mTimer.cancel();
} catch (NoSuchObjectLocalException | NullPointerException ex) {
System.out.println("There is no timer running.");
}
}
}
但是,在我尝试将实体添加到项目后出现了问题。我的实体看起来像这样:
@Entity
public class TestEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String testValue;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTestValue() {
return testValue;
}
public void setTestValue(String value) {
testValue = value;
}
// removed standard code for @Override of equals(),
// hashCode() & toString()
}
我通过我的控制器bean操作:
@Stateless
public class TestDBController {
@PersistenceContext(unitName = "TimerTestWithDBPU")
private EntityManager em;
public long saveValue(String value) {
TestEntity entity = new TestEntity();
entity.setTestValue(value);
em.persist(entity);
em.flush();
return entity.getId();
}
public String getValue(long aId) {
TestEntity entity = em.find(TestEntity.class, aId);
return entity.getTestValue();
}
}
我按以下方式设置了持久性单元(persistence.xml):
<?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 name="TimerTestWithDBPU" transaction-type="JTA">
<jta-data-source>jdbc/timer_test_pool</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.schema-generation.database.action"
value="create"/>
</properties>
</persistence-unit>
</persistence>
添加此实体和持久性单元后,我收到以下错误:
EJB Timer Service is not available.
Timers for application with id [XYZ] will not be deleted
这是为什么?你不能用ejb定时器和持久实体运行一个应用程序吗?
答案 0 :(得分:0)
事实证明,你可以!谁会砸它......
Glassfish App Dev Guide中的这句话指出了我正确的方向。
使用EJB Timer Service等同于与单个JDBC资源管理器交互。如果EJB组件或应用程序直接通过JDBC或间接访问数据库(例如,通过实体bean的持久性机制),并且还与EJB Timer Service交互,则必须使用XA JDBC驱动程序配置其数据源。
我将尝试描述我的所作所为(我是Java EE世界中的新手,因此某些概念和功能名称可能不正确)
事实证明,在我的情况下,您需要在应用程序服务器(Payara)中配置资源,以便它使用XA JDBC驱动程序而不是普通的JDBC驱动程序。 (我不完全理解为什么如果有人愿意详细说明我很乐意听到它)
要做到这一点:
ConnectionPool需要连接到JDBC资源并获取服务器的JNDI名称才能使用它。在Payara的管理页面中:
现在在Persistence Unit(persistance.xml)中添加新连接池作为项目的DataSource。
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="htt...>
<persistence-unit name="TimerTestPU" transaction-type="JTA">
<jta-data-source>jdbc/TestPool</jta-data-source> <!-- Magic Line -->
.
.
.
</persistence-unit>
</persistence>
此时我开始工作了。然而,似乎仍然存在问题,因为如果我运行其他使用计时器的应用程序,同时仍然使用非XA JBDC驱动程序的数据库,它实际上打破了我的工作。这表明无法Ping默认的__TimerPool连接池,出现以下错误(如果有人能说明这一点,我会全力以赴):
java.lang.NoClassDefFoundError: Could not initialize class
org.apache.derby.jdbc.EmbeddedDriver Could not initialize class
org.apache.derby.jdbc.EmbeddedDriver
我最终删除了ejb驱动程序的默认连接池(__TimerPool)并创建了一个新的,使用与上面相同的过程(1-10),但名称如“TimerEJB”。要使其正常工作,您需要“安装”数据库,这意味着创建适合应用程序服务器的标准数据库。 Payara和Glassfish为此提供了SQL:
%install-path-of-payara%\glassfish\lib\install\databases\
选择文件ejbtimer_ [VENDOR_NAME] .sql并在您创建的数据库上运行此文件。在此之后,您应该将此作为ejb计时器的默认连接工具。在Payaras管理页面:
现在重启所有内容,或者至少重新启动Payara和数据库服务器,你应该好好去。
最后一部分的灵感来自@ejohansson's answer相关问题。
希望这有助于某人:)