DAO模式+ JNDI数据+ CDI与MyBatis

时间:2017-02-14 10:13:13

标签: java hibernate jpa mybatis ibatis

我打算从我的项目中删除JPA(Eclipselink)并使用MyBatis而不是它。我正在寻找一些很好的指南,在EE容器(statelass session ejb)和JNDI数据源+ DAO模式+ CDI(我不使用Spring!)中使用MyBatis的最佳实践是什么。不幸的是,我没有找到任何关于它的好文档。

有没有办法初始化MyBatis并使用没有xml配置文件的JNDI数据源?

使用CDI实现DAO模式并将我的dao类注入无状态EJB的最佳MyBatis方法是什么?

我使用Java 8 + Glassfish(Payara EE服务器)+ MyBatis 3.4.2。

UPDATE-1

我按照此页http://www.mybatis.org/cdi/getting-started.html上的说明操作,但它对我不起作用。

这是我使用Glassfish(实际上是Payara)应用服务器时的运行时异常:

[2017-02-14T22:02:23.715+0100] [Payara 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=101 _ThreadName=admin-listener(6)] [timeMillis: 1487106143715] [levelValue: 800] [[
  Loading application [mybatis-demo-1.0#mybatis-demo-war-1.0.war] at [/demo]]]

[2017-02-14T22:02:23.770+0100] [Payara 4.1] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=101 _ThreadName=admin-listener(6)] [timeMillis: 1487106143770] [levelValue: 800] [[
  mybatis-demo-1.0 was successfully deployed in 1,526 milliseconds.]]

[2017-02-14T22:03:00.333+0100] [Payara 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=25 _ThreadName=http-listener-1(2)] [timeMillis: 1487106180333] [levelValue: 800] [[
  WebModule[null] ServletContext.log():Marking servlet a.b.war.HelloServlet as unavailable]]

[2017-02-14T22:03:00.334+0100] [Payara 4.1] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=25 _ThreadName=http-listener-1(2)] [timeMillis: 1487106180334] [levelValue: 900] [[
  StandardWrapperValve[a.b.war.HelloServlet]: Allocate exception for servlet a.b.war.HelloServlet
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type PersonMapper with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private a.b.war.HelloServlet.personMapper
  at a.b.war.HelloServlet.personMapper(HelloServlet.java:0)

这是我的测试servlet:

@WebServlet("/servlet")
public class HelloServlet extends HttpServlet {
    @Inject
    private PersonMapper personMapper;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().println(personMapper.getPerson(1L).toString());
    }

我的映射器类:

@Mapper
public interface PersonMapper {
    @Select("SELECT * FROM person WHERE id = #{id}")
    Person getPerson(@Param("id") long id);
}

似乎永远不会调用MyBatisSQLSessionFactory.getSqlSessionFactory()方法,因为我在日志文件中看不到任何内容。

我的SessionFactory类:

public class MyBatisSQLSessionFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisSQLSessionFactory.class);

    @Produces
    @ApplicationScoped
    @SessionFactoryProvider
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        LOGGER.info("MyBatis is initializing...");
        String resource = "mybatis-configuration.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        LOGGER.info("MyBatis has been initialized, SQL Session Factory: {}", sqlSessionFactory.toString());
        return sqlSessionFactory;
    }
}

最后我的战争结构:

*.war
│   index.html
│
├───META-INF
│   │   bean.xml
│   │   MANIFEST.MF
│   │
│   └───maven
│         ...
│
└───WEB-INF
    ├───classes
    │   └───a
    │       └───b
    │           └───war
    │               │   HelloServlet.class
    │               │
    │               └───mybatis
    │                   │   MyBatisSQLSessionFactory.class
    │                   │
    │                   └───dao
    │                           PersonMapper.class
    │
    └───lib

也许我弄错了,我忘记了......

UPDATE-2

"如果没有至少一个适当的CDI bean使用,Weld不会检测映射器。而Servlet不是合适的CDI bean。 解决方法是使用@Dependent注释servlet。" 您可以找到更多详细信息here

2 个答案:

答案 0 :(得分:1)

我在这里的答案,也是为了清楚起见我的评论。

不是第一个问题,但可能是下一个问题:至少在类路径中需要mybatis-configuration.xml来定义transactionManager和引用jndi dataSource。

以防万一为MyBatisSQLSessionFactory添加一个带默认构造函数的默认构造函数。应该只实例化一次。

对于WAR,beans.xml必须位于WEB-INF中。否则,在单独的依赖项ejb.jar中提取业务代码,所有这些都打包在EAR中。

我建议激活JTA Transactions:填充beans.xml。

我在EJB中使用@Inject @SessionFactory protected SqlSession session;,然后在其方法中使用new DAO(session);,因为事务是在EJB级别上管理的,并且注入会话的DAO注入不能按预期工作。

当有多个语句被调用时,还要注释EJB方法@Transactional(executorType=ExecutorType.REUSE)。这将使用相同的连接;所有交易报表的ction,只准备一次唯一的报表。首先尝试不弄清楚。

答案 1 :(得分:0)

是的,有一种很好的方法可以在Java EE环境中使用myBatis,尤其是CDI。

有一个mybatis-cdi扩展,可以为您解决许多问题并确保完美集成。 GitHub repository is here并链接到official documentation.

您应该彻底阅读official documentation。特别是“入门”部分(在介绍之后的左侧菜单中)。他们解释了如何设置一切。

此外,还有一个很好的示例项目to be found on GitHub。甚至有example with JSF used