gpt4 book ai didi

java - 如何使用 EJB 3.0 实现适当的计数器 bean?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:28:59 25 4
gpt4 key购买 nike

[编辑] 这个问题是“如何使用 EJB 3 和 JPA 2.0 对实体 bean 进行原子更改”。应该很简单吧?

我尝试根据目前得到的答案修复我的代码。我正在使用 JBoss 6.0.0M2 和 Hypersonic(只需下载并调用 run.bat)。

我的测试用例:创建 3 个线程并在循环中调用其中一个 testCounterMitLock*() 500 次。所以一个成功的测试应该打印“Anzahl eingetragene Zeilen: 1500” (3*500)。

我试过:

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1);
manager.lock(ct, LockModeType.WRITE);
int wert = ct.getWert();

显然是行不通的,因为不同的线程可以在应用锁之前更改数据库中的值。所以我尝试解决这个问题:

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1);
manager.lock(ct, LockModeType.WRITE);
manager.refresh (ct);
int wert = ct.getWert();

refresh() 应该给我当前值并且隐式查询还应该确保对象现在被锁定。没有这样的运气。让我们尝试使用 JPA 2.0:

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.WRITE);
int wert = ct.getWert();

那也行不通。也许锁还不够?

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.PESSIMISTIC_WRITE);
int wert = ct.getWert();

嗯……也不行!最后一次绝望的尝试:

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.PESSIMISTIC_WRITE);
manager.flush();
manager.refresh (ct);
int wert = ct.getWert();

好的...谁能解释为什么什么都不起作用?我没主意了。

[EDIT2] PS:雪上加霜的是,这是最后一个运行线程的最后输出:

commit/rollback: 441/62

(441+62 = 503)...

这是完整的代码。首先是 bean :

package server.kap15;

import java.rmi.RemoteException;

import javax.ejb.*;
import javax.persistence.*;

@Stateful
public class CounterTestBean implements CounterTestRemote, SessionSynchronization {
@PersistenceContext(unitName = "JavaEE")
EntityManager manager;

private int commit = 0;

private int rollback = 0;

public void initDatenbank() {
manager.createNamedQuery("CounterTest.deleteAll").executeUpdate();
manager.createNamedQuery("TestTabelle.deleteAll").executeUpdate();
CounterTestVersion ct = new CounterTestVersion();
ct.setNr(1);
ct.setVersion(1);
ct.setWert(1);
manager.persist(ct);
}

public boolean testCounterOhneLock() {
try {
CounterTest ct = manager.find(CounterTest.class, 1);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitLock() {
try {
CounterTestVersion ct = manager.find(CounterTestVersion.class, 1);
manager.lock(ct, LockModeType.WRITE);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitLock2() {
try {
CounterTestVersion ct = manager.find(CounterTestVersion.class, 1);
manager.lock(ct, LockModeType.WRITE);
manager.refresh (ct);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitLock3() {
try {
CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.WRITE);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitLock4() {
try {
CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.PESSIMISTIC_WRITE);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitLock5() {
try {
CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.PESSIMISTIC_WRITE);
manager.flush();
manager.refresh (ct);
int wert = ct.getWert();
ct.setWert(wert + 1);
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (Throwable t) {
return false;
}
}

public boolean testCounterMitVersion() {
try {
CounterTestVersion ctv = manager.find(CounterTestVersion.class, 1);
int wert = ctv.getWert();
ctv.setWert(wert + 1);
manager.flush();
TestTabelle tt = new TestTabelle();
tt.setNr(wert);
manager.persist(tt);
manager.flush();
return true;
} catch (OptimisticLockException e) {
System.out.println(">>> Versionskonflikt !");
return false;
} catch (Throwable t) {
System.out.println(t.getMessage());
return false;
}
}

public long anzTestZeilen() {
Query query = manager.createNamedQuery("TestTabelle.anzZeilen");
Long anzahl = (Long) query.getSingleResult();
return anzahl;
}

public void afterBegin() throws EJBException, RemoteException {
}

public void beforeCompletion() throws EJBException, RemoteException {
}

public void afterCompletion(boolean committed) throws EJBException,
RemoteException {
if (committed)
commit++;
else
rollback++;
System.out.println("commit/rollback: " + commit + "/" + rollback);
}
}

远程接口(interface):

package server.kap15;

import javax.ejb.Remote;

@Remote
public interface CounterTestRemote {
public void initDatenbank();

public boolean testCounterOhneLock();

public boolean testCounterMitLock();
public boolean testCounterMitLock2();
public boolean testCounterMitLock3();
public boolean testCounterMitLock4();
public boolean testCounterMitLock5();

public boolean testCounterMitVersion();

public long anzTestZeilen();
}

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="JavaEE">
<jta-data-source>java:DefaultDS</jta-data-source>
</persistence-unit>
</persistence>

测试客户端:

package client.kap15;

import java.util.Properties;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import server.kap15.CounterTestRemote;

public class CounterTestMitLock extends Thread {
CounterTestRemote ctr;

public static void main(String[] args) {
try
{
testMitLock();
testMitLock2();
testMitLock3();
testMitLock4();
testMitLock5();
}
catch (Exception e)
{
e.printStackTrace ();
}
}

static int N = 3;
static CounterThread[] ct = new CounterThread[N];

private static void testMitLock () throws InterruptedException
{
System.out.println("--- Counter Test MIT Lock ----------------------");
System.out.println("Testinstanzen erzeugen...");
for (int i=0; i<N; i++)
ct[i] = new CounterThreadMitLock();

runTest ();
}

private static void testMitLock2 () throws InterruptedException
{
System.out.println("--- Counter Test MIT Lock2 ----------------------");
System.out.println("Testinstanzen erzeugen...");
for (int i=0; i<N; i++)
ct[i] = new CounterThreadMitLock2();

runTest ();
}

private static void testMitLock3 () throws InterruptedException
{
System.out.println("--- Counter Test MIT Lock3 ----------------------");
System.out.println("Testinstanzen erzeugen...");
for (int i=0; i<N; i++)
ct[i] = new CounterThreadMitLock3();

runTest ();
}

private static void testMitLock4 () throws InterruptedException
{
System.out.println("--- Counter Test MIT Lock4 ----------------------");
System.out.println("Testinstanzen erzeugen...");
for (int i=0; i<N; i++)
ct[i] = new CounterThreadMitLock4();

runTest ();
}

private static void testMitLock5 () throws InterruptedException
{
System.out.println("--- Counter Test MIT Lock5 ----------------------");
System.out.println("Testinstanzen erzeugen...");
for (int i=0; i<N; i++)
ct[i] = new CounterThreadMitLock5();

runTest ();
}

private static void runTest () throws InterruptedException
{
System.out.println("Datenbank initialisieren...");
ct[0].ctr.initDatenbank();

System.out.println("Test durchführen...");
for (int i=0; i<N; i++)
ct[i].start();

System.out.println("Auf Ende warten...");
for (int i=0; i<N; i++)
ct[i].join();

System.out.println("Anzahl eingetragene Zeilen: " + ct[0].ctr.anzTestZeilen());
}

private static CounterTestRemote verbinden() {
try {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
p.put(Context.PROVIDER_URL, "jnp://localhost:1099");
Context ctx = new InitialContext(p);

Object ref = ctx.lookup("CounterTestBean/remote");
CounterTestRemote ctr = (CounterTestRemote) PortableRemoteObject.narrow(ref, CounterTestRemote.class);

return ctr;
} catch (NamingException e) {
System.out.println("ERROR - NamingException!");
System.exit(-1);
}
return null;
}

public abstract static class CounterThread extends Thread
{
protected CounterTestRemote ctr;

public CounterThread ()
{
this.ctr = verbinden ();
}

public void run() {
for (int i = 0; i < 500; i++)
test ();
}

public abstract void test ();
}

public static class CounterThreadMitLock extends CounterThread
{
@Override
public void test ()
{
this.ctr.testCounterMitLock();
}

}

public static class CounterThreadMitLock2 extends CounterThread
{
@Override
public void test ()
{
this.ctr.testCounterMitLock2();
}

}

public static class CounterThreadMitLock3 extends CounterThread
{
@Override
public void test ()
{
this.ctr.testCounterMitLock3();
}

}

public static class CounterThreadMitLock4 extends CounterThread
{
@Override
public void test ()
{
this.ctr.testCounterMitLock4();
}

}

public static class CounterThreadMitLock5 extends CounterThread
{
@Override
public void test ()
{
this.ctr.testCounterMitLock5();
}

}
}

最佳答案

由于所有锁定模式都不起作用,我尝试了 ewernli使用手动 SELECT ... FOR UPDATE 的解决方案。这给出了一个有趣的异常(exception):“意外的 token FOR”。所以我查看了数据库。

JBoss 安装有 Hypersonic 1.8 (HSQLDB) 默认不支持行锁定。亲爱的 JBoss 开发人员:当不支持锁定模式时,JPA 实现应该抛出异常。

所以我添加了一个 Oracle 数据源并更改了我的 persistence.xml。之后,两个测试工作:

        CounterTestVersion ct = manager.find(CounterTestVersion.class, 1, LockModeType.PESSIMISTIC_WRITE);
int wert = ct.getWert();

    Query query = manager.createNativeQuery ("select * from COUNTER_TEST where NR = 1 for update", CounterTestVersion.class);
CounterTestVersion ct = (CounterTestVersion)query.getSingleResult ();
int wert = ct.getWert ()+1;

这很有趣。它也应该与 LockModeType.PESSIMISTIC_FORCE_INCREMENT 一起使用。在这种情况下,我在日志中看到了这个错误:

ORA-00054: resource busy and acquire with NOWAIT specified

这发生在调用 manager.find() 中。我不明白为什么两者在加载阶段表现不同。可能是 JBoss 或 Hibernate 中的错误。

关于java - 如何使用 EJB 3.0 实现适当的计数器 bean?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2551128/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com