Jakarta ee MyBatis CDI+;容器管理事务

Jakarta ee MyBatis CDI+;容器管理事务,jakarta-ee,cdi,mybatis,ear,ibatis,Jakarta Ee,Cdi,Mybatis,Ear,Ibatis,我想在我的应用程序中使用mybatis和容器管理事务。我使用mybatis 3.4.2和mybatis cdi 1.0.0 我的代码可以工作,但目前我手动打开和关闭会话,不知道如何将SqlSession或Mapper注入我的EJB 在我的情况下,mybatis cdi似乎不能正常工作 这是我的部署结构: EAR +--- commons.jar (interfaces, POJOs) +--- ejb.jar (stateless EJBs + MyBatis mapper + sess

我想在我的应用程序中使用mybatis和容器管理事务。我使用mybatis 3.4.2和mybatis cdi 1.0.0

我的代码可以工作,但目前我手动打开和关闭会话,不知道如何将
SqlSession
Mapper
注入我的EJB

在我的情况下,
mybatis cdi
似乎不能正常工作

这是我的部署结构:

EAR
  +--- commons.jar (interfaces, POJOs)
  +--- ejb.jar (stateless EJBs + MyBatis mapper + session factory)
  +--- web.war (demo servlet which calls EJB)
commons.jar

/a/
/a/b/
/a/b/commons/
/a/b/commons/mybatis/
/a/b/commons/mybatis/SessionFactoryProducer.class
/a/b/commons/api/
/a/b/commons/api/EchoService.class
/a/b/commons/domain/
/a/b/commons/domain/Configuration.class
/META-INF/
/META-INF/beans.xml
/a/
/a/b/
/a/b/ejb/
/a/b/ejb/EchoServiceBean.class
/a/b/ejb/dao/
/a/b/ejb/dao/ConfigurationDao.class
/a/b/ejb/SessionFactoryProducerImpl.class
/META-INF/
/META-INF/beans.xml
SessionFactoryProducer.java(生成SqlSessionFactory的简单接口)

EchoService.java(EJB接口)

Configuration.java(简单POJO)

beans.xml

<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <interceptors>
        <class>org.mybatis.cdi.JtaTransactionInterceptor</class>
    </interceptors>

</beans>
same then before
EchoServiceBean.java(简单无状态EJB)

java(简单的MyBatis映射器,这里没有什么特别的)

SessionFactoryProducerImpl.java(EJB,产生MyBatis SqlSessionFactory):

beans.xml

<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <interceptors>
        <class>org.mybatis.cdi.JtaTransactionInterceptor</class>
    </interceptors>

</beans>
same then before
当我使用我的
SessionFactoryProducerImpl
EJB来获取MyBatis会话时,一切正常,但我想让EE容器管理SqlSession(打开/关闭/提交/回滚)

这个问题是在我按照官方文件的建议修改了我的
SessionFactoryProducerImpl
之后出现的(删除@Stateless和接口引用,添加@products、@ApplicationScoped、@SessionFactoryProvider注释),之后

  • 我注入了
    org.apache.ibatis.session.SqlSession
    而不是我的
    sessionfactoryproduceripl
    在将EAR部署到服务器的过程中,我得到了一个
    类型SqlSession与qualifiers@Default
    的未满足的依赖项
  • 我注入MyBatis映射器,它是
    ConfigurationDao
    ,在我的例子中,然后我得到一个
    错误,没有正确配置的SqlSessionFactory生产者
  • 让EE容器管理MyBatis会话的正确方法是什么


    更新-1

    我尝试按名称插入SqlSessionFactory:

    //@Stateless
    public class SessionFactoryProducerImpl /*implements SessionFactoryProducer*/ {
        //@Override
        @ApplicationScoped
        @Produces
        @Named("fooManager")
        @SessionFactoryProvider
        public SqlSessionFactory produce() throws IOException {
           ...
        }
    }
    
    用法:

    @Stateless
    public class EchoServiceBean implements EchoService {
        @Inject @Named("fooManager") ConfigurationDao configurationDao;
        ...
    }
    
    从应用服务器登录:

    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172749] [levelValue: 800] [[
      MyBatis CDI Module - Found class with @Mapper-annotation: ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172943] [levelValue: 800] [[
      MyBatis CDI Module - SqlSessionFactory producer SessionFactoryProducerImpl.produce]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172982] [levelValue: 800] [[
      MyBatis CDI Module - Activated]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172983] [levelValue: 800] [[
      MyBatis CDI Module - Found a bean, which needs a Mapper interface a.b.ejb.dao.ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172984] [levelValue: 800] [[
      MyBatis CDI Module - Managed Mapper dependency: a.b.ejb.dao.ConfigurationDao_fooManager, a.b.ejb.dao.ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172984] [levelValue: 800] [[
      MyBatis CDI Module - Managed SqlSession: org.apache.ibatis.session.SqlSession_fooManager, org.apache.ibatis.session.SqlSession]]
    
    [Payara 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972173275] [levelValue: 800] [[
      Loading application [ear-packager-1.0#web-1.0.war] at [/web]]]
    
    [Payara 4.1] [INFO] [javax.enterprise.system.core] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972173334] [levelValue: 800] [[
      ear-packager-1.0 was successfully deployed in 1,280 milliseconds.]]
    
    但当我尝试使用它时,仍然会出现异常:

    Caused by: org.mybatis.cdi.MybatisCdiConfigurationException: There are no SqlSessionFactory producers properly configured.
        at org.mybatis.cdi.CDIUtils.findSqlSessionFactory(CDIUtils.java:55)
        at org.mybatis.cdi.SerializableMapperProxy.getMapper(SerializableMapperProxy.java:57)
        at org.mybatis.cdi.SerializableMapperProxy.<init>(SerializableMapperProxy.java:44)
        at org.mybatis.cdi.MyBatisBean.create(MyBatisBean.java:116)
        at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:70)
        at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
        at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
        at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:744)
        at org.jboss.weld.manager.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:844)
        at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:92)
        at org.jboss.weld.util.Beans.injectBoundFields(Beans.java:362)
        at org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:373)
        at org.jboss.weld.injection.producer.DefaultInjector$1.proceed(DefaultInjector.java:71)
        at org.glassfish.weld.services.InjectionServicesImpl.aroundInject(InjectionServicesImpl.java:173)
        at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:46)
        at org.jboss.weld.injection.producer.DefaultInjector.inject(DefaultInjector.java:73)
        at org.jboss.weld.injection.producer.StatelessSessionBeanInjector.inject(StatelessSessionBeanInjector.java:60)
        at org.jboss.weld.injection.producer.ejb.SessionBeanInjectionTarget.inject(SessionBeanInjectionTarget.java:140)
        at org.glassfish.weld.services.JCDIServiceImpl.injectEJBInstance(JCDIServiceImpl.java:261)
        at com.sun.ejb.containers.BaseContainer.injectEjbInstance(BaseContainer.java:1698)
        at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:488)
        ... 50 more
    
    我可以看到我的
    SessionFactoryProducerImpl
    被注入@Stateless注释(bean id 70)或不注入@Stateless注释。我还可以看到SQLSessionFactoryProducer也被注入了bean id 58

    但是我仍然得到
    org.mybatis.cdi.mybatiscdigurationexception:当我调用EJB的
    echo(…)
    方法时,没有正确配置的SqlSessionFactory生产者


    我猜MyBatis需要使用
    a.b.ejb.SessionFactoryProducerImpl
    中的producer方法。但是如何告诉mybatis cdi呢?

    文档没有告诉您删除
    @Stateless
    ,只是没有指定它是必需的,因为它描述了一般用例。然后尝试:

    @Stateless
    @Local(SessionFactoryProducer.class)
    public class SessionFactoryProducerImpl implements SessionFactoryProducer {
        //@Override
        @ApplicationScoped
        @Produces
        @Named("fooManager")
        @SessionFactoryProvider
        public SqlSessionFactory produce() throws IOException {
           ...
        }
    }
    
    @Local(SessionFactoryProducer.class)
    实现SessionFactoryProducer
    甚至可能不是必需的

    我假设
    @Stateless
    SessionFactoryProducer
    转换成一个EJB,该EJB将在相同的上下文/范围中可用,并可以注入到另一个上下文/范围中

    SessionFactoryProducer
    只需出席即可。之后,CDI的任务是在找到SqlSession或Mapper注入点时调用它

    这就是我所做的,会话由EJB管理。当然提供了mybatis-config.xml:

    <environments default="development">
      <environment id="development">
        <transactionManager type="MANAGED">
        <dataSource type="JNDI">
    
    
    
    首先,尝试部署示例应用程序。它已经在许多应用服务器上进行了测试,并且有一个示例EJB。然后只需将mybatis-config_1.xml更改为使用托管事务。会话工厂生产者不打算直接使用,而是由mybatis cdi内部使用。链接到示例应用程序:你是正确的。“@Local”和“implement”关键字不是必需的。正如我所见,“@无状态”也不是必需的。正如您在UPDATE-2中看到的,SqlSessionFactory被注入,但仍然会出现错误:(我的mybatis.xml与您的非常相似。神奇的是,只需要注释,CDI就可以完成所有工作。我认为无论如何都需要
    @Stateless
    :即使SessionFactoryProducer被实例化,它也无法访问(不同的范围…这是错误日志所说的)要调用并用SqlSession/Mapper注入EJB,
    @Stateless
    将其转换为EJB,这与使用简单webapp(无EJB)时不同。您使用的是哪种应用服务器?我使用的是Jboss EAP 6.3
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172749] [levelValue: 800] [[
      MyBatis CDI Module - Found class with @Mapper-annotation: ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172943] [levelValue: 800] [[
      MyBatis CDI Module - SqlSessionFactory producer SessionFactoryProducerImpl.produce]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172982] [levelValue: 800] [[
      MyBatis CDI Module - Activated]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172983] [levelValue: 800] [[
      MyBatis CDI Module - Found a bean, which needs a Mapper interface a.b.ejb.dao.ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172984] [levelValue: 800] [[
      MyBatis CDI Module - Managed Mapper dependency: a.b.ejb.dao.ConfigurationDao_fooManager, a.b.ejb.dao.ConfigurationDao]]
    
    [Payara 4.1] [INFO] [org.mybatis.cdi.MybatisExtension] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972172984] [levelValue: 800] [[
      MyBatis CDI Module - Managed SqlSession: org.apache.ibatis.session.SqlSession_fooManager, org.apache.ibatis.session.SqlSession]]
    
    [Payara 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972173275] [levelValue: 800] [[
      Loading application [ear-packager-1.0#web-1.0.war] at [/web]]]
    
    [Payara 4.1] [INFO] [javax.enterprise.system.core] [tid: _ThreadID=803 _ThreadName=admin-thread-pool::admin-listener(40)] [timeMillis: 1492972173334] [levelValue: 800] [[
      ear-packager-1.0 was successfully deployed in 1,280 milliseconds.]]
    
    Caused by: org.mybatis.cdi.MybatisCdiConfigurationException: There are no SqlSessionFactory producers properly configured.
        at org.mybatis.cdi.CDIUtils.findSqlSessionFactory(CDIUtils.java:55)
        at org.mybatis.cdi.SerializableMapperProxy.getMapper(SerializableMapperProxy.java:57)
        at org.mybatis.cdi.SerializableMapperProxy.<init>(SerializableMapperProxy.java:44)
        at org.mybatis.cdi.MyBatisBean.create(MyBatisBean.java:116)
        at org.jboss.weld.context.unbound.DependentContextImpl.get(DependentContextImpl.java:70)
        at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.get(ContextualInstanceStrategy.java:100)
        at org.jboss.weld.bean.ContextualInstance.get(ContextualInstance.java:50)
        at org.jboss.weld.manager.BeanManagerImpl.getReference(BeanManagerImpl.java:744)
        at org.jboss.weld.manager.BeanManagerImpl.getInjectableReference(BeanManagerImpl.java:844)
        at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:92)
        at org.jboss.weld.util.Beans.injectBoundFields(Beans.java:362)
        at org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:373)
        at org.jboss.weld.injection.producer.DefaultInjector$1.proceed(DefaultInjector.java:71)
        at org.glassfish.weld.services.InjectionServicesImpl.aroundInject(InjectionServicesImpl.java:173)
        at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:46)
        at org.jboss.weld.injection.producer.DefaultInjector.inject(DefaultInjector.java:73)
        at org.jboss.weld.injection.producer.StatelessSessionBeanInjector.inject(StatelessSessionBeanInjector.java:60)
        at org.jboss.weld.injection.producer.ejb.SessionBeanInjectionTarget.inject(SessionBeanInjectionTarget.java:140)
        at org.glassfish.weld.services.JCDIServiceImpl.injectEJBInstance(JCDIServiceImpl.java:261)
        at com.sun.ejb.containers.BaseContainer.injectEjbInstance(BaseContainer.java:1698)
        at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:488)
        ... 50 more
    
    @WebServlet("/cdi")
    public class CdiServlet extends HttpServlet {
    
        @Inject
        BeanManager beanManager;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            Set<Bean<?>> beans = beanManager.getBeans(Object.class, new AnnotationLiteral<Any>() {});
    
            ...
        }
    }
    
    (4)
    toString(): Extension [class org.mybatis.cdi.MybatisExtension] with qualifiers [@Default]; jar:file:/home/soma/applications/servers/_gombi_/payara-middleware/glassfish/domains/domain1/applications/ear-packager-1.0/lib/mybatis-cdi-1.0.0.jar!/META-INF/services/javax.enterprise.inject.spi.Extension@1[org.mybatis.cdi.MybatisExtension@643ecfa7]
    getName(): org.mybatis.cdi.MybatisExtension
    getSimpleName(): MybatisExtension
    getSuperclass(): class java.lang.Object
    getPackage(): org.mybatis.cdi
    getAnnotations(): []
    
    
    (6)
    toString(): Managed Bean [class org.mybatis.cdi.CDIUtils$SerializableAnyAnnotationLiteral] with qualifiers [@Any @Default]
    getName(): org.mybatis.cdi.CDIUtils$SerializableAnyAnnotationLiteral
    getSimpleName(): SerializableAnyAnnotationLiteral
    getSuperclass(): class javax.enterprise.util.AnnotationLiteral
    getPackage(): org.mybatis.cdi
    getAnnotations(): []
    
    (8)
    toString(): Extension [class org.glassfish.cdi.transaction.TransactionalExtension] with qualifiers [@Default]; bundle://302.0:0/META-INF/services/javax.enterprise.inject.spi.Extension@1[org.glassfish.cdi.transaction.TransactionalExtension@665874cc]
    getName(): org.glassfish.cdi.transaction.TransactionalExtension
    getSimpleName(): TransactionalExtension
    getSuperclass(): class java.lang.Object
    getPackage(): org.glassfish.cdi.transaction
    getAnnotations(): []
    
    (18)
    toString(): Managed Bean [class org.mybatis.cdi.SqlSessionManagerRegistry] with qualifiers [@Any @Default]
    getName(): org.mybatis.cdi.SqlSessionManagerRegistry
    getSimpleName(): SqlSessionManagerRegistry
    getSuperclass(): class java.lang.Object
    getPackage(): org.mybatis.cdi
    getAnnotations(): [@javax.enterprise.context.ApplicationScoped()]
    
    (35)
    toString(): Managed Bean [class org.mybatis.cdi.CDIUtils] with qualifiers [@Any @Default]
    getName(): org.mybatis.cdi.CDIUtils
    getSimpleName(): CDIUtils
    getSuperclass(): class java.lang.Object
    getPackage(): org.mybatis.cdi
    getAnnotations(): []
    
    (46)
    toString(): Managed Bean [class a.b.commons.domain.Configuration] with qualifiers [@Any @Default]
    getName(): a.b.commons.domain.Configuration
    getSimpleName(): Configuration
    getSuperclass(): class java.lang.Object
    getPackage(): a.b.commons.domain
    getAnnotations(): []
    
    (48)
    toString(): Session bean [class a.b.ejb.EchoServiceBean with qualifiers [@Any @Default]; local interfaces are [EchoService]
    getName(): a.b.ejb.EchoServiceBean
    getSimpleName(): EchoServiceBean
    getSuperclass(): class java.lang.Object
    getPackage(): a.b.ejb
    getAnnotations(): [@javax.ejb.Stateless(name=, description=, mappedName=)]
    
    (55)
    toString(): Managed Bean [class org.mybatis.cdi.CDIUtils$SerializableDefaultAnnotationLiteral] with qualifiers [@Any @Default]
    getName(): org.mybatis.cdi.CDIUtils$SerializableDefaultAnnotationLiteral
    getSimpleName(): SerializableDefaultAnnotationLiteral
    getSuperclass(): class javax.enterprise.util.AnnotationLiteral
    getPackage(): org.mybatis.cdi
    getAnnotations(): []
    
    
    (56)
    toString(): Managed Bean [class a.b.web.CdiServlet] with qualifiers [@Any @Default]
    getName(): a.b.web.CdiServlet
    getSimpleName(): CdiServlet
    getSuperclass(): class javax.servlet.http.HttpServlet
    getPackage(): a.b.web
    getAnnotations(): [@javax.servlet.annotation.WebServlet(loadOnStartup=-1, initParams=[], urlPatterns=[], displayName=, largeIcon=, name=, asyncSupported=false, description=, smallIcon=, value=[/cdi])]
    
    (58)
    toString(): Producer Method [SqlSessionFactory] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @ApplicationScoped @Produces @SessionFactoryProvider public a.b.ejb.SessionFactoryProducerImpl.produce()]
    getName(): a.b.ejb.SessionFactoryProducerImpl
    getSimpleName(): SessionFactoryProducerImpl
    getSuperclass(): class java.lang.Object
    getPackage(): a.b.ejb
    getAnnotations(): []
    
    (70)
    toString(): Managed Bean [class a.b.ejb.SessionFactoryProducerImpl] with qualifiers [@Any @Default]
    getName(): a.b.ejb.SessionFactoryProducerImpl
    getSimpleName(): SessionFactoryProducerImpl
    getSuperclass(): class java.lang.Object
    getPackage(): a.b.ejb
    getAnnotations(): []
    
    72)
    toString(): Managed Bean [class a.b.commons.domain.Configuration] with qualifiers [@Any @Default]
    getName(): a.b.commons.domain.Configuration
    getSimpleName(): Configuration
    getSuperclass(): class java.lang.Object
    getPackage(): a.b.commons.domain
    getAnnotations(): []
    
    @Stateless
    @Local(SessionFactoryProducer.class)
    public class SessionFactoryProducerImpl implements SessionFactoryProducer {
        //@Override
        @ApplicationScoped
        @Produces
        @Named("fooManager")
        @SessionFactoryProvider
        public SqlSessionFactory produce() throws IOException {
           ...
        }
    }
    
    <environments default="development">
      <environment id="development">
        <transactionManager type="MANAGED">
        <dataSource type="JNDI">