持久感知 KieSession 在事务期间不使用悲观锁

Persistent aware KieSession not using Pessimistic Lock during transactions

我正在使用 DroolsSpring Boot 2.3,我已经实现了持久感知 KieSession,其中MySQL用于存储session。我已经成功地将 Spring Boot 的默认值 EntityManagerFactory 与 Drools 集成,但我的问题是交易。默认情况下,Drools 在事务期间使用乐观锁,但它也允许我们使用悲观锁,这正是我想要的。现在,在触发规则时,Drools persists/updates MySQL 中的 KieSession 使用以下查询:

update SessionInfo set lastModificationDate=?, rulesByteArray=?, startDate=?, OPTLOCK=? where id=? and OPTLOCK=?

现在,如果我不使用方法中使用 @Transactional 注释的事务,上述语句将执行两次,如果使用 @Transactional,则上述语句仅在触发后执行一次规则。

现在,如果我手动更改 OPTLOCK 字段的值,Drools 会抛出异常:

javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [org.drools.persistence.info.SessionInfo#1]

其次是:

Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [org.drools.persistence.info.SessionInfo#1]

由于此处的文本长度限制,我无法 post 整个 Stacktrace。整个堆栈跟踪可以在 this GitHub project.

中查看

我不确定 Drools 是否在使用环境中定义的悲观锁。关于我的会话实现,我想要一个 KieSession 因为我使用 KieSession 作为 Bean.

下面是我的实现:

配置class:

@Configuration
public class DynamicDroolsConfig {

    private KieServices kieServices;
    private KieFileSystem kieFileSystem;

    @Autowired
    private PersistentSessionDAO persistentSessionDAO;
    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;


    @PostConstruct
    private void init() {
        this.kieServices = KieServices.Factory.get();
        this.kieFileSystem = kieServices.newKieFileSystem();
    }

    @Bean
    public KieServices getKieServices() {
        return this.kieServices;
    }

    @Bean
    public KieContainer getKieContainer() {
        kieFileSystem.write(ResourceFactory.newClassPathResource("rules/rules.drl"));
        final KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
        KieBuilder kb = kieServices.newKieBuilder(kieFileSystem).buildAll();
        KieModule kieModule = kb.getKieModule();
        return kieServices.newKieContainer(kieModule.getReleaseId());
    }

    @Bean
    public KieFileSystem getFileSystem() {
        return kieFileSystem;
    }

    @Bean
    public KieSession kieSession() {
        List<SessionInfo> sessionDetails = persistentSessionDAO.getSessionDetails();

        if (sessionDetails.size() == 0) {
            return kieServices.getStoreServices().newKieSession(getKieContainer().getKieBase(), null, getEnv());
        } else {
            return kieServices.getStoreServices().loadKieSession(sessionDetails.get(0).getId(), getKieContainer().getKieBase(), null, getEnv());
        }
    }

    private Environment getEnv() {
        Environment env = kieServices.newEnvironment();
        env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
        env.set(EnvironmentName.TRANSACTION_MANAGER, platformTransactionManager);
        env.set(EnvironmentName.USE_PESSIMISTIC_LOCKING, true);
        env.set(EnvironmentName.USE_PESSIMISTIC_LOCKING_MODE, LockModeType.PESSIMISTIC_FORCE_INCREMENT.name());
        return env;
    }
}

控制器class:

@RestController
public class MyController {

    @Autowired
    private KieSession kieSession;

    @Transactional
    @GetMapping("fire-person")
    public void firePerson() {
        Person person = new Person();
        person.setName("Christy");
        kieSession.insert(person);
        kieSession.fireAllRules();
    }
}

事实class

public class Person implements Serializable {

    private String name;
    private int age;
    private String gender;
    private String toCompareName;
    private String toCompareGender;

    // getters and setters
}

存储库界面:

public interface DroolsSessionRepository extends JpaRepository<SessionInfo, Long> {
}

服务class:

@Service
public class PersistentSessionDAO {

    @Autowired
    private DroolsSessionRepository droolsSessionRepository;

    public List<SessionInfo> getSessionDetails() {
        return droolsSessionRepository.findAll();
    }
}

亚军class:

@EntityScan(basePackages = {"com.sam.springdroolspersistence.entity", "org.drools.persistence.info"})
@EnableJpaRepositories
@SpringBootApplication
public class SpringDroolsPersistenceApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringDroolsPersistenceApplication.class, args);
    }
}

使用的 Drools 依赖项:

        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-persistence-jpa</artifactId>
            <version>${drools-version}</version>
        </dependency>

        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <version>${drools-version}</version>
        </dependency>

        <dependency>
            <groupId>org.jbpm</groupId>
            <artifactId>jbpm-persistence-jpa</artifactId>
            <version>${drools-version}</version>
        </dependency>

代码实现也可以在this GitHub Project中找到。任何形式的 help/suggestions 都将不胜感激。谢谢。

悲观锁定仅在 JBPM 中实现,请参阅 here

Drools 持久性中没有这样的功能,SessionInfo 将始终使用基于 JPA 的 @Version 注释的 OptimisticLocking。

如果您需要此类功能,请在 Drools 上提交功能请求 Jira