如何解决持久感知 KieSession 在事务期间不使用悲观锁
我正在将 Drools 与 Spring Boot 2.3 一起使用,并且我已经实现了持久感知 KieSession
,其中使用了 MySQL用于存储会话。我已经成功地将 Spring Boot 的默认 EntityManagerFactory
与 Drools 集成,但我的问题是事务。默认情况下,Drools 在事务期间使用乐观锁,但它也允许我们使用悲观锁,这正是我想要的。现在,在触发规则时,Drools 使用以下查询持久/更新 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]
由于此处的文本长度限制,我无法发布整个 Stacktrace。可以在 this GitHub project 中查看整个堆栈跟踪。
我不确定 Drools 是否使用了环境中定义的悲观锁。关于我的会话实现,我想要一个 KieSession
,因为我使用 KieSession 作为 Bean
。
以下是我的实现:
配置类:
@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(),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;
}
}
控制器类:
@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();
}
}
事实类
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> {
}
服务类:
@Service
public class PersistentSessionDAO {
@Autowired
private DroolsSessionRepository droolsSessionRepository;
public List<SessionInfo> getSessionDetails() {
return droolsSessionRepository.findAll();
}
}
跑步类:
@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中找到。任何形式的帮助/建议将不胜感激。谢谢。
解决方法
悲观锁定仅在 JBPM 中实现,参见 here
Drools 持久化中没有这样的功能,SessionInfo
将始终使用基于 JPA 的 @Version
注释的 OptimisticLocking。
如果您需要此类功能,请在 Drools 的 Jira
上提交功能请求版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。