首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MyBatis CDI +容器管理事务

MyBatis CDI +容器管理事务
EN

Stack Overflow用户
提问于 2017-04-23 17:24:56
回答 1查看 1.9K关注 0票数 0

我想在我的应用中使用带有容器管理事务的mybatis。我使用mybati3.4.2和mybatis 1.0.0。

我的代码可以工作,但目前我手动打开和关闭会话,并且不知道如何将SqlSessionMapper注入到EJB中。

在我的情况下,mybatis-cdi似乎没有做好它的工作。

,这是我的部署结构:

代码语言:javascript
复制
EAR
  +--- commons.jar (interfaces, POJOs)
  +--- ejb.jar (stateless EJBs + MyBatis mapper + session factory)
  +--- web.war (demo servlet which calls EJB)

commons.jar

代码语言:javascript
复制
/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

SessionFactoryProducer.java (生产SqlSessionFactory的简单接口)

代码语言:javascript
复制
public interface SessionFactoryProducer {
    SqlSessionFactory produce() throws IOException;
}

EchoService.java (EJB接口)

代码语言:javascript
复制
public interface EchoService {
    String echo(String str) throws IOException;
}

Configuration.java (简单POJO)

代码语言:javascript
复制
class with getters/setters

beans.xml

代码语言:javascript
复制
<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>

ejb.jar

代码语言:javascript
复制
/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

EchoServiceBean.java (简单无状态EJB)

代码语言:javascript
复制
@Stateless
public class EchoServiceBean implements EchoService {

    //@Inject
    //private SessionFactoryProducer sqlSessionFactoryProducer;

    //@Inject
    //private SqlSession sqlSession;

    @Inject
    private ConfigurationDao configurationDao;

    @Override
    public String echo(String str) throws IOException {
        // SqlSession sqlSession = sqlSessionFactoryProducer.produce().openSession();
        // ConfigurationDao configurationDao = sqlSession.getMapper(ConfigurationDao.class);
        Configuration configuration = configurationDao.findByKey("something");
        LOGGER.info(configuration.toString());

        sqlSession.close();
        return new Date() + ": Hello";
    }
}

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

代码语言:javascript
复制
@Mapper
public interface ConfigurationDao {
    @Select("SELECT id, key_name, key_value, description "
            + "FROM application.configuration "
            + "WHERE key_name = #{key}")
    Configuration findByKey(@Param("key") String key);
}

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

代码语言:javascript
复制
@Stateless
public class SessionFactoryProducerImpl implements SessionFactoryProducer {
    @Override
    public SqlSessionFactory produce() throws IOException {
        LOGGER.info("MyBatis SessionFactory is initializing...");

        try (Reader reader = Resources.getResourceAsReader("mybatis.xml")) {
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
            LOGGER.info("Session factory has been obtained");
            return sessionFactory;
        }
    }
}

beans.xml

代码语言:javascript
复制
same then before

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

根据官方文档SessionFactoryProducerImpl的建议(删除@无状态和接口引用,添加@Produces,@ApplicationScoped,@SessionFactoryProvider注释)之后,出现了这个问题。

  1. 我注入org.apache.ibatis.session.SqlSession而不是我的SessionFactoryProducerImpl,我在部署EAR到服务器时得到了一个Unsatisfied dependencies for type SqlSession with qualifiers @Default
  2. 我注入MyBatis映射器,在我的例子中是ConfigurationDao,然后我得到一个There are no SqlSessionFactory producers properly configured错误。

让EE容器管理MyBatis会话的正确方法是什么?

更新-1

我试着用名字注入SqlSessionFactory:

代码语言:javascript
复制
//@Stateless
public class SessionFactoryProducerImpl /*implements SessionFactoryProducer*/ {
    //@Override
    @ApplicationScoped
    @Produces
    @Named("fooManager")
    @SessionFactoryProvider
    public SqlSessionFactory produce() throws IOException {
       ...
    }
}

用法:

代码语言:javascript
复制
@Stateless
public class EchoServiceBean implements EchoService {
    @Inject @Named("fooManager") ConfigurationDao configurationDao;
    ...
}

从app服务器登录:

代码语言:javascript
复制
[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.]]

但当我尝试使用它时,我还是会有例外:

代码语言:javascript
复制
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

知道我的代码有什么问题吗?

更新-2

有趣的事。我刚刚向war项目添加了一个新的servlet,以显示CDI容器中可用bean的列表:

代码语言:javascript
复制
@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>() {});

        ...
    }
}

我可以看到,在我的EE容器中有74个bean,最重要的bean是:

代码语言:javascript
复制
(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(): []

我可以看到,我的SessionFactoryProducerImpl被注入了@无状态注释(bean id 70)。我还可以看到,SqlSessionFactory生产者也被注入,bean id 58。

但是,当我调用我的org.mybatis.cdi.MybatisCdiConfigurationException: There are no SqlSessionFactory producers properly configuredecho(...)方法时,仍然会得到echo(...)错误。

我想MyBatis需要使用a.b.ejb.SessionFactoryProducerImpl的producer方法。但如何告诉玛提-CDI呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-24 18:58:31

文档没有要求删除@Stateless,只是没有指定它是必需的,因为它描述了通用用例。然后试着:

代码语言:javascript
复制
@Stateless
@Local(SessionFactoryProducer.class)
public class SessionFactoryProducerImpl implements SessionFactoryProducer {
    //@Override
    @ApplicationScoped
    @Produces
    @Named("fooManager")
    @SessionFactoryProvider
    public SqlSessionFactory produce() throws IOException {
       ...
    }
}

@Local(SessionFactoryProducer.class)implements SessionFactoryProducer甚至可能不是强制性的。

我认为@Stateless会将SessionFactoryProducer转换为EJB,然后在相同的上下文/作用域中可用,并可以将其注入另一个上下文/作用域。

SessionFactoryProducer只是被要求在场。之后,这是CDI在找到SqlSession或Mapper注入点时调用它的工作。

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

代码语言:javascript
复制
<environments default="development">
  <environment id="development">
    <transactionManager type="MANAGED">
    <dataSource type="JNDI">
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43574276

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档