3

在我们对使用 jackrabbit 的应用程序进行了一些性能测试之后,我们面临着并发修改 jackrabbit 存储库的巨大问题。当我们在多线程仿真中添加节点或编辑它们时会出现问题。然后我写了一个非常简单的测试,它告诉我们问题不在我们的环境中。

有它:

简单的无状态 Bean

     @无状态
        @Local(TestFacadeLocal.class)
        @Remote(TestFacadeRemote.class)
        公共类 TestFacadeBean 实现 TestFacadeRemote,TestFacadeLocal {
            公共无效doAction(int name)抛出异常{
                新的 TestSynch().doAction(name);
            }
        }

简单类

    公共类TestSynch {
        公共无效doAction(int name)抛出异常{
            会话 session = ((Repository) new InitialContext().
                    查找("java:jcr/local")).login(
                    new SimpleCredentials("username", "pwd".toCharArray()));
            添加列表 = new ArrayList();
            节点文件夹 = session.getRootNode().getNode("test");
            for (int i = 0; i <= 100; i++) {
                子节点 = folder.addNode("" + System.currentTimeMillis(),
                              “nt:文件夹”);
                child.addMixin("mix:versionable");

                添加.add(child);
            }
            // 保存 butch 更改
            session.save();

            //检查所有创建的节点
            对于(节点节点:添加){
                session.getWorkspace().getVersionManager().checkin(node.getPath());
            }
        }
    }

和测试类

    公共类测试{
        私人int c = 0;
        私人int countAll = 50;
        private ExecutorService executor = Executors.newFixedThreadPool(5);

        公共 ExecutorService getExecutor() {
            返回执行者;
        }

        公共静态无效主要(字符串[]参数){
            测试 test = new Test();
            尝试 {
                test.start();
            } 捕捉(异常 e){
                e.printStackTrace();
            }
        }

        私人无效开始()抛出异常{
            长时间 = System.currentTimeMillis();
            TestFacadeRemote testBean = (TestFacadeRemote) getContext().
                                        查找(“测试/TestFacadeBean/远程”);
            for (int i = 0; i < countAll; i++) {
                getExecutor().execute(new TestInstallerThread(i, testBean));
            }

            getExecutor().shutdown();
            while (!getExecutor().isTerminated()) {
                尝试 {
                    线程.sleep(500);
                } 捕捉(InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println(c + " 关机 " +
                               (System.currentTimeMillis() - 时间));

        }

        类 TestInstallerThread 实现 Runnable {
            私人整数 = 0;
            TestFacadeRemote testBean;

            公共 TestInstallerThread(int number, TestFacadeRemote testBean) {
                this.number = 数字;
                this.testBean = testBean;
            }

            @覆盖
            公共无效运行(){
                尝试 {
                    System.out.println("安装数据" + number);
                    testBean.doAction(数字);
                    System.out.println("STOP" + number);
                } 捕捉(异常 e){
                    e.printStackTrace();
                    C++;
                }
            }

        }

        公共上下文 getContext() 抛出 NamingException {
            属性属性 = 新属性();
            //初始化道具
            .....................
            返回新的 InitialContext(属性);
        }
    }

如果我用池中的 1 个线程初始化 executor,所有这些都没有任何错误。如果我用 5 个线程初始化执行程序,有时会出现错误:

在客户端

    java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] 无法提交因为交易处于中止状态
        在 org.jboss.aspects.tx.TxPolicy.handleEndTransactionException(TxPolicy.java:198)

开始时在服务器上警告

    ItemStateReferenceCache [ItemStateReferenceCache.java:176] 覆盖缓存条目 187554a7-4c41-404b-b6ee-3ce2a9796a70

接着

    javax.jcr.RepositoryException: org.apache.jackrabbit.core.state.ItemStateException: 已经有一个 id 为 52fb4b2c-3ef4-4fc5-9b79-f20a6b2e9ea3/{http://www.jcp.org/jcr/1.0 的属性状态实例}创建
        在 org.apache.jackrabbit.core.PropertyImpl.restoreTransient(PropertyImpl.java:195) ~[jackrabbit-core-2.2.7.jar:2.2.7]
        在 org.apache.jackrabbit.core.ItemSaveOperation.restoreTransientItems(ItemSaveOperation.java:879) [jackrabbit-core-2.2.7.jar:2.2.7]

我们已尝试将此方法和其他工作流程同步,以将多线程调用作为一个线程处理。没有什么帮助。

还有一件事——当我们在没有 ejb 层的情况下做了类似的测试时——一切都很好。看起来容器包装在自己的事务中,然后全部崩溃。

也许有人面临这样的问题。提前致谢。

4

1 回答 1

5

来自Jackrabbit 维基

JCR 规范明确声明 Session 不是线程安全的(JCR 1.0 第 7.5 节和 JCR 2.0 第 4.1.2 节)。因此,Jackrabbit 不支持多个线程同时读取或写入同一会话。每个会话只能从一个线程访问。

...如果需要同时写入同一个节点,那么就需要使用多个会话,并使用JCR锁来保证不冲突。

于 2011-11-07T12:11:00.797 回答