无法在Spring Boot中实现Drools KieSession持久性

如何解决无法在Spring Boot中实现Drools KieSession持久性

我试图在Spring Boot Maven项目中使用KieSession的持久性功能来实现Drools。遵循this documentation进行实施。可以在普通的Java应用程序中做到这一点,但是在Spring Boot应用程序中尝试这样做时却出现异常。

下面是实现。

项目结构

enter image description here

配置类

@Configuration
public class PersistentDroolConfig {

    public static Long KIE_SESSION_ID;
    private final KieServices kieServices = KieServices.Factory.get();

    @Bean
    public KieSession kieSession() {
        KieSession kieSession = kieServices.getStoreServices().newKieSession(getKieBase(),null,getEnv());
        PersistentDroolConfig.KIE_SESSION_ID = kieSession.getIdentifier();
        return kieSession;
    }

    public KieServices getKieServices() {
        initDataSource();
        return kieServices;
    }

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

    public Environment getEnv() {
        Environment env = kieServices.newenvironment();
        env.set(EnvironmentName.ENTITY_MANAGER_FACTORY,Persistence.createEntityManagerFactory("org.drools.persistence.jpa"));
        env.set(EnvironmentName.TRANSACTION_MANAGER,TransactionManagerServices.getTransactionManager());
        return env;
    }

    private void initDataSource() {
        PoolingDataSource ds = new PoolingDataSource();
        ds.setUniqueName("jdbc/BitronixJTADataSource");
        ds.setClassName("com.MysqL.cj.jdbc.MysqLXADataSource");
        ds.setMaxPoolSize(3);
        ds.setAllowLocalTransactions(true);
        ds.getDriverProperties().put("user","root");
        ds.getDriverProperties().put("password","1234");
        ds.getDriverProperties().put("URL","jdbc:MysqL://localhost:3306/drool_demo");
        ds.init();
    }
}

控制器类

@RestController
public class OfferController {

    @Autowired
    private KieSession kieSession;

    @GetMapping("/order/{card-type}/{price}")
    public Order order(@PathVariable("card-type") String cardType,@PathVariable int price) {
        Order order = new Order(cardType,price);
        kieSession.insert(order);
        kieSession.fireAllRules();
        return order;
    }
}

情况介绍

public class Order implements Serializable {

    private String name;
    private String cardType;
    private int discount;
    private int price;

    public Order(String cardType,int price) {
        this.cardType = cardType;
        this.price = price;
    }

    // setters and getters

    // toString()
}

persistence.xml

<persistence version="2.0"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd
                      http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
    xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="org.drools.persistence.jpa"
        transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/BitronixJTADataSource</jta-data-source>
        <class>org.drools.persistence.info.SessionInfo</class>
        <class>org.drools.persistence.info.WorkItemInfo</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MysqLDialect" />
            <property name="hibernate.max_fetch_depth" value="3" />
            <property name="hibernate.hbm2ddl.auto" value="create" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
        </properties>
    </persistence-unit>
</persistence>

pom.xml 文件中包含的依赖项如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>MysqL</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.github.marcus-nl.btm</groupId>
            <artifactId>btm</artifactId>
            <version>3.0.0-mk1</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-decisiontables</artifactId>
            <version>${drools-version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>${drools-version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>${drools-version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-persistence-jpa</artifactId>
            <version>${drools-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

错误堆栈跟踪:

Caused by: org.hibernate.engine.jndi.JndiException: Unable to lookup JNDI name [jdbc/BitronixJTADataSource]

Caused by: javax.naming.NameNotFoundException: unable to find a bound object at name 'jdbc/BitronixJTADataSource'

该项目也可以在this repository中找到。

更新1:

实现@jccampanero的答案后,我有了更新的堆栈跟踪:

Caused by: org.hibernate.HibernateException: Unable to perform isolated work

Caused by: java.sql.sqlSyntaxErrorException: Table 'drool_demo.sessioninfo_id_seq' doesn't exist

更新2:

进一步研究之后,我发现Drools由于语法错误而没有制作必要的表。由于Stackoverflow具有文本限制,因此仅在此处发布了重要的异常消息。就是这样:

Hibernate: drop table if exists SessionInfo
Hibernate: drop table if exists WorkItemInfo
Hibernate: create table SessionInfo (id bigint not null auto_increment,lastModificationDate datetime,rulesByteArray longblob,startDate datetime,OPTLOCK integer,primary key (id)) type=MyISAM
2020-10-09 23:49:59.554  WARN 11376 --- [           main] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL "create table SessionInfo (id bigint not null auto_increment,primary key (id)) type=MyISAM" via JDBC Statement


org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table SessionInfo (id bigint not null auto_increment,primary key (id)) type=MyISAM" via JDBC Statement

Caused by: java.sql.sqlSyntaxErrorException: You have an error in your sql Syntax; check the manual that corresponds to your MysqL server version for the right Syntax to use near 'type=MyISAM' at line 1

Hibernate: create table WorkItemInfo (workItemId bigint not null auto_increment,creationDate datetime,name varchar(255),processInstanceId bigint not null,state bigint not null,workItemByteArray longblob,primary key (workItemId)) type=MyISAM
2020-10-09 23:49:59.556  WARN 11376 --- [           main] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL "create table WorkItemInfo (workItemId bigint not null auto_increment,primary key (workItemId)) type=MyISAM" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table WorkItemInfo (workItemId bigint not null auto_increment,primary key (workItemId)) type=MyISAM" via JDBC Statement

Caused by: java.sql.sqlSyntaxErrorException: You have an error in your sql Syntax; check the manual that corresponds to your MysqL server version for the right Syntax to use near 'type=MyISAM' at line 1

解决方法

您是否在容器中配置了jndi数据源?

<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
    maxTotal="100" maxIdle="30" maxWaitMillis="10000"
    username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/javatest"/>

Tomcat jndi data source example

,

我认为您的配置有问题。 getKieServices类的PersistentDroolConfig方法永远不会被调用,因此,initDataSource方法也不会初始化您的数据源。

也许您可以尝试修改PersistentDroolConfig,如下所示:

@Configuration
public class PersistentDroolConfig {

    public static Long KIE_SESSION_ID;

    private KieServices kieServices;

    @PostContruct
    private void init() {
        this.initDataSource();
        this.kieServices = KieServices.Factory.get();
    }

    @Bean
    public KieSession kieSession() {
        KieSession kieSession;
        if (KIE_SESSION_ID == null) {
            kieSession = createNewKieSession();
            KIE_SESSION_ID = kieSession.getIdentifier();
            return kieSession;
        } else {
            kieSession = getPersistentKieSession();
            KIE_SESSION_ID = kieSession.getIdentifier();
            return kieSession;
        }
    }

    public KieBase getKieBase() {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource("rules/rules.drl"));
        final KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(new KieModule() {
            @Override
            public ReleaseId getReleaseId() {
                return kieRepository.getDefaultReleaseId();
            }
        });
        KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
        kb.buildAll();
        KieModule kieModule = kb.getKieModule();
        KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
        KieBase kieBase = kieContainer.getKieBase();
        return kieBase;
    }

    public Environment getEnv() {
        Environment env = kieServices.newEnvironment();
        env.set(EnvironmentName.ENTITY_MANAGER_FACTORY,Persistence.createEntityManagerFactory("org.drools.persistence.jpa"));
        env.set(EnvironmentName.TRANSACTION_MANAGER,TransactionManagerServices.getTransactionManager());
        return env;
    }

    private KieSession createNewKieSession() {
        KieSession kieSession = kieServices.getStoreServices().newKieSession(getKieBase(),null,getEnv());
        PersistentDroolConfig.KIE_SESSION_ID = kieSession.getIdentifier();
        return kieSession;
    }

    private KieSession getPersistentKieSession() {
        return kieServices.getStoreServices().loadKieSession(KIE_SESSION_ID,getKieBase(),getEnv());
    }

    private void initDataSource() {
        PoolingDataSource ds = new PoolingDataSource();
        ds.setUniqueName("jdbc/BitronixJTADataSource");
        ds.setClassName("com.mysql.cj.jdbc.MysqlXADataSource");
        ds.setMaxPoolSize(3);
        ds.setAllowLocalTransactions(true);
        ds.getDriverProperties().put("user","root");
        ds.getDriverProperties().put("password","1234");
        ds.getDriverProperties().put("URL","jdbc:mysql://localhost:3306/drool_demo");
        ds.init();
    }
}

更新

如不同评论中所述,进行了这些更改之后,出现了与SESSIONINFO_ID_SEQ序列有关的问题,该序列用于生成实体SessionInfo的字段id的值。 / p>

问题似乎与使用的Hibernate和MySQL版本有关。

要解决该问题,必须对persistence.xml文件进行几处更改。

首先,应包含以下属性:

<property name="hibernate.id.new_generator_mappings" value="false" />

在Drools示例和test cases中经常使用它。有关详细说明,请参见this Vlad Mihalcea的出色文章。

此配置属性的包含产生了一个与所使用的MySQL方言有关的新问题。它应该更改为:

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>

使用此配置,应用程序应该可以平稳运行。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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元字符(。)和普通点?