我在Spring Boot 2.3中使用Drools,并且实现了持久感知的会话,其中MySQL用于存储会话。我已经成功地将Spring Boot的默认< code > entitymanager factory 与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。可以在此GitHub项目中查看整个堆栈跟踪。
我不确定Drools是否使用了环境中定义的悲观锁。关于我的会话实现,我希望有一个< code>KieSession,因为我将KieSession用作< code>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(), 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;
}
}
控制器类:
@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>
代码实现也可以在这个GitHub项目中找到。任何帮助/建议都将不胜感激。谢谢你。
悲观锁定仅在JBPM中实现
Drools持久性中没有这种功能,< code>SessionInfo将始终使用基于JPA的< code>@Version注释的OptimisticLocking。
如果您需要此类功能,请在Drools的Jira上提交功能请求
我需要使用悲观锁执行批处理操作,以便在此操作期间没有其他人可以读取或写入此行。但是我想在每批之后增加页码,以便如果事务失败或实例死亡,我将从最后一页继续。但是使用下面的代码,它不会更新页面,直到所有批处理完成,所以当重新启动作业时,它会从页面=0开始处理。 有没有办法在每批启用悲观_写后更新页面? 提前谢谢。
我在一个游戏服务器上使用Hibernate for ORM,刚刚从每个工作单元的会话/事务切换到每个请求的会话/事务。 由于多个事务可能相互冲突,因此我使用悲观锁定。问题是我经常遇到僵局。现在我的问题是,是否可以在锁定特定实体实例的事务中显式定义范围,或者在指定锁定模式后是否锁定实例直到我提交事务? 如果后者成立,如果我不能任意调度锁定数据库中资源的方法的方法调用,我如何避免每个请求环境中的会话事
我正在使用Spring Boot、JPA、Oracle 12C和下面的类型化查询来选择要处理的“新”项目。一旦我选择了“新”项目,我就会更新其状态,使其不再符合选择条件,但我看到一个并发问题,相同的项目被选中。 我在这里读到,我需要设置一个'LockModeType.PESSIMISTIC_WRITE'的查询,以防止其他线程选择相同的行,但它似乎不起作用。 我是否遗漏了下面的内容,或者我是否需要另
我使用Spring缓存抽象使用Ehache作为缓存提供程序。我试图将缓存操作附加到Spring JPA事务,但无法这样做。 即使事务失败/回滚缓存放发生。 配置, springcache-abs-ehcache。xml, 雇员安置处, 事务方法, 测试用例(调用者), 测试应该成功,也就是说,如果事务在该方法中回滚,Spring不应该将数据放入方法中的缓存中。但是,即使事务失败,Spring也会将
我知道悲观锁定与锁定数据库记录,并在获得锁的“交易”结束时释放它。但这是否意味着悲观锁定是在物理交易中,例如 开始交易 提交事务? 对于一个网页,当用户选择要编辑的记录时,当他按下编辑按钮时,我想悲观地锁定此记录,以便其他人无法更改它,然后在编辑按钮onpress()事件中,我开始物理事务? 似乎是不可能的,因为编辑过程可能很长......它在整个编辑过程中保持数据库事务(按编辑按钮,在网页中编辑
我创建了一个扩展服务并作为前台服务运行的类。我希望我的服务通知是持久的(即不通过刷卡删除)。但是,我的通知可以通过刷卡来撤销。 服务留档指出:...前台服务必须为状态栏提供通知,状态栏放在正在进行的标题下。这意味着除非服务停止或从前台删除,否则通知不能被驳回... 我确实设置了断点来检查是否命中了onDestroy()或stop Self(),但事实并非如此。该服务正在前台模式下运行,但我可以通过