ConcurrentModificationException持久化Spring

如何解决ConcurrentModificationException持久化Spring

我需要在Spring应用程序中使用drools持久性,但是我遇到了从不同线程并行访问多个kie会话的问题。

实际上,这种行为是意外的,有时我会出现 ConcurrentModificationException ,有时会出现 NullPointerException 。我写了一个小实验项目:https://github.com/sibmaks/drools_spring_persistance

测试: singleSessionWritesTest 总是可以正常工作,因为我在顺序模式下处理一个kie会话,但是 multipleWritesTest 却出现错误

框架版本:

流口水:7.43.1。最终

春季:1.5.8。发布

有人可以提示我哪里做错了,或者我必须阅读以解决此问题?

P.S。代码

Bean配置:

//...

@Configuration
public class DroolsConfig {

//...

   @Bean
   @Qualifier("droolsEnvironment")
   public Environment droolsEnvironment(
           @Qualifier("droolsDataSource") DataSource dataSource,//@Qualifier("drools-entityManagerFactory")
           //        LocalContainerEntityManagerfactorybean droolsEntityManagerFactory,KieServices kieServices) {
       LocalContainerEntityManagerfactorybean droolsEntityManagerFactory = new LocalContainerEntityManagerfactorybean();
       droolsEntityManagerFactory.setDataSource(dataSource);
       droolsEntityManagerFactory.setPersistenceUnitName("drools.cookbook.persistence.jpa");
       droolsEntityManagerFactory.afterPropertiesSet();

       JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(droolsEntityManagerFactory.getobject());
       jpaTransactionManager.setnestedTransactionAllowed(false);
       jpaTransactionManager.afterPropertiesSet();

       TransactionManager transactionManager = new KieSpringTransactionManager(jpaTransactionManager);

       Environment environment = kieServices.newenvironment();
       environment.set(EnvironmentName.ENTITY_MANAGER_FACTORY,droolsEntityManagerFactory.getobject());
       environment.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER,new KieSpringJpaManager(environment));
       environment.set(EnvironmentName.TRANSACTION_MANAGER,transactionManager);
       environment.set(EnvironmentName.GLOBALS,new MapGlobalResolver());
       return environment;
   }

/...
}

获取或加载kie会话代码

    protected KieSessionContainer getorCreate(String externalId) {
        if (!kieSessionMap.containsKey(externalId)) {
            creationLock.lock();
            try {
                if (!kieSessionMap.containsKey(externalId)) {
                    ClientKieSession clientKieSession = clientKieSessionRepository.findFirstByClientId(externalId);
                    KieSession kieSession;
                    if (clientKieSession == null) {
                        log.info("**** Create session for client: {}",externalId);
                        kieSession = droolsService.createSession(externalId);
                    } else {
                        log.info("**** Restore session for client: {}",externalId);
                        try {
                            kieSession = droolsService.loadSession(clientKieSession.getSessionIdentifier());
                        } catch (Exception e) {
                            log.error("**** Restore session for error,create new session",e);
                            clientKieSessionRepository.delete(clientKieSession);
                            return droolsService.getorCreate(externalId);
                        }
                    }
                    kieSession.addEventListener(new EventHandler());
                    kieSessionMap.put(externalId,new KieSessionContainer(kieSession,new reentrantlock()));
                }
            } finally {
                creationLock.unlock();
            }
        }
        return kieSessionMap.get(externalId);
    }

    @Transactional
    protected KieSession createSession(String externalId) {
        KieSession kieSession = kieStoreServices.newKieSession(kieBase,kieSessionConfiguration,environment);
        ClientKieSession clientKieSession = new ClientKieSession();
        clientKieSession.setSessionIdentifier(kieSession.getIdentifier());
        clientKieSession.setClientId(externalId);
        clientKieSession.setCreated(Timestamp.valueOf(LocalDateTime.Now()));
        clientKieSessionRepository.save(clientKieSession);
        return kieSession;
    }

    @Transactional
    protected KieSession loadSession(long identifier) {
        return kieStoreServices.loadKieSession(identifier,kieBase,environment);
    }

实际插入代码(产生异常)

    @Transactional
    protected void processFacts(KieSession kieSession,Object ... facts) {
        for(Object fact : facts) {
            kieSession.execute(CommandFactory.newInsert(fact));
        }
        kieSession.fireAllRules();
    }

测试代码

        Random random = new Random();
        Executor executor = Executors.newFixedThreadPool(16);
        List<String> ids = new ArrayList<>();
        for(int i = 0; i < 16; i++) {
            ids.add(UUID.randomUUID().toString());
        }
        AtomicInteger counter = new AtomicInteger();
        AtomicInteger finished = new AtomicInteger();
        long time = System.currentTimeMillis();
        AtomicBoolean exception = new AtomicBoolean();
        for(int i = 0; i < COUNT; i++) {
            executor.execute(() -> {
                if(exception.get()) {
                    return;
                }
                try {
                    droolsService.processFacts(ids.get(random.nextInt(ids.size())),new LongFact(counter.incrementAndGet()));
                    finished.incrementAndGet();
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                    exception.set(true);
                }
            });
        }
        while (finished.get() != COUNT && !exception.get()) {
            TimeUnit.MILLISECONDS.sleep(100);
        }
        long end = System.currentTimeMillis();
        log.info("{} execution time. {} op per second",(end - time),(0.0 + end - time) / COUNT);

        int result = 0;
        int resultQ = 0;
        for(String id : ids) {
            result += droolsService.sessionDump(id).stream().filter(it -> it instanceof LongFact).count();
            resultQ += droolsService.processQuery(id,"getLongs").size();
        }
        Assert.assertEquals(COUNT,result);
        Assert.assertEquals(COUNT,resultQ);

例外示例:

java.util.ConcurrentModificationException: null
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[na:1.8.0_191]
    at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[na:1.8.0_191]
    at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042) ~[na:1.8.0_191]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:580) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1300) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_191]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at com.sun.proxy.$Proxy115.flush(UnkNown Source) ~[na:na]
    at org.drools.persistence.TriggerUpdateTransactionSynchronization.beforeCompletion(TriggerUpdateTransactionSynchronization.java:76) ~[drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.kie.spring.persistence.SpringTransactionSynchronizationAdapter.beforeCompletion(SpringTransactionSynchronizationAdapter.java:54) ~[kie-spring-7.43.1.Final.jar:7.43.1.Final]
    at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCompletion(TransactionSynchronizationUtils.java:106) ~[spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCompletion(AbstractPlatformTransactionManager.java:945) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:745) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.kie.spring.persistence.KieSpringTransactionManager.commit(KieSpringTransactionManager.java:70) [kie-spring-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:608) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:565) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.command.impl.CommandBasedStatefulKNowledgeSession.execute(CommandBasedStatefulKNowledgeSession.java:537) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.example.drools_persistance_spring.service.DroolsService.processFacts(DroolsService.java:74) [main/:na]
    at org.example.drools_persistance_spring.service.DroolsService.processFacts(DroolsService.java:64) [main/:na]
    at org.example.drools_persistance_spring.service.DroolsServiceTest.lambda$multipleWritesTest$2(DroolsServiceTest.java:84) [test/:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_191]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_191]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_191]

一个异常(重启测试后)

javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: -1; expected: 1
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1729) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1634) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1303) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_191]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at com.sun.proxy.$Proxy115.flush(UnkNown Source) ~[na:na]
    at org.drools.persistence.TriggerUpdateTransactionSynchronization.beforeCompletion(TriggerUpdateTransactionSynchronization.java:76) ~[drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.kie.spring.persistence.SpringTransactionSynchronizationAdapter.beforeCompletion(SpringTransactionSynchronizationAdapter.java:54) ~[kie-spring-7.43.1.Final.jar:7.43.1.Final]
    at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCompletion(TransactionSynchronizationUtils.java:106) ~[spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCompletion(AbstractPlatformTransactionManager.java:945) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:745) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) [spring-tx-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.kie.spring.persistence.KieSpringTransactionManager.commit(KieSpringTransactionManager.java:70) [kie-spring-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:608) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:565) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68) [drools-persistence-jpa-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.drools.core.command.impl.CommandBasedStatefulKNowledgeSession.execute(CommandBasedStatefulKNowledgeSession.java:537) [drools-core-7.43.1.Final.jar:7.43.1.Final]
    at org.example.drools_persistance_spring.service.DroolsService.processFacts(DroolsService.java:74) [main/:na]
    at org.example.drools_persistance_spring.service.DroolsService.processFacts(DroolsService.java:64) [main/:na]
    at org.example.drools_persistance_spring.service.DroolsServiceTest.lambda$multipleWritesTest$2(DroolsServiceTest.java:84) [test/:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_191]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_191]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_191]
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: -1; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3134) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3013) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3393) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:145) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1300) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    ... 26 common frames omitted

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?