zoukankan      html  css  js  c++  java
  • 解决 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 以及MyBatis批量加载xml映射文件的方式

      错误 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 的出现,意味着项目需要xml文件来映射SQL语句,如果只使用接口进行SQL映射,不在本文讨论范围内。

      我的项目的环境是IDEA下的Maven工程,而IDEA下的MAVEN工程中有一个特点就是,在src/main/java中,只有.java文件默认会被编译,而xml文件不会被编译。(出处)

      的确这样的做法也比较符合Maven目录框架的初衷:即在src/main/java中只存放.java的源码文件。

      在使用MyBatis Generator进行逆向生成时是可以指定mapper接口和对应的xml文件的位置的,有的人也喜欢把它们指定在java目录下的同一个包(如:src/main/java/com/abc/mapper)中,而我就喜欢指定在不同的目录下(接口文件:src/main/java/com/abc/mapper,xml文件:scr/mian/resources/mapper)。我们分开讨论

    一、Mapper接口文件和对应的XML在同一个目录下

      一般来说,接口文件和XML文件是同名一一对应的。

      这种情况就是要改变IDEA中MAVEN工程默认不编译src/main/java中的xml文件的行为,需要在maven的pom.xml中配置一个节点:

    <project>
            ......
            <build>
                <resources>
            <resource>
                <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>true</filtering>
                </resource>
            </resources>
            </build>
    </project>

      这样IDEA就会对src/main/java中的xml文件进行编译了。

      我的工程中进行相应的修改后,的确奏效了。

      但是我项目中MyBatis的核心配置文件中,配置是空的,没有指定任何xml的位置:

    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
    </configuration>

      然后发现,在Spring容器中创建SqlSessionFactory的Bean时(在applicationContext-dao.xml中),就已经指定了Mapper接口的位置:

    <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 数据库连接池 -->
            <property name="dataSource" ref="dataSource" />
            <!-- 加载mybatis的全局核心配置文件 -->
            <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
        </bean>
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.taotao.mapper" />
        </bean>

      在上面的配置中,如果我去掉第二个bean,应用就无法正常启动。报错的内容大概是这样:因为那些Mapper接口没有被注册为Bean,所以在Service层中的相关类中的属性的自动注入没法完成,因为找不到那些Mapper的bean。事实上,在Spring的配置文件中使用这个MapperScannerConfigurer类我也是第一次碰到,查了一下,这个类就是进行Bean的定义工作——“从接口的基础包开始递归搜索,并将它们注册为MapperFactoryBean。 请注意,仅注册具有至少一种方法的接口; 具体类将被忽略”。

      而我自己习惯的做法是,在applicationContext-dao.xml中进行如下声明,把MyBatis的相关映射接口注册为Bean:

    <!--将指定的包中所有接口当作mapper来配置,之后可以自动引入mapper类-->
      <mybatis:scan base-package="com.biguo.mapper"/>

      所以需要确保把Mapper接口注册为Bean,不论用哪种方式,都是可以的,而同目录下的xml文件是被自动加载。

      第一种情况的解决方案就是这样。

    二、Mapper接口文件和对应的XML在不同的目录下

      如下图,我习惯的做法是在进行MyBatis逆向生成时,把Mapper接口放在src/main/java下,把对应的XML文件放到src/main/resources下,分开存放。

       mapper接口是一定要注册为Bean的,上面提到的两种方式都可以。

      然后就是,告诉MyBatis去哪里找到哪些映射SQL语句的XML文件,最最常用的就是在MyBatis 的核心配置文件中使用<mappers>标签进行指定。官方文档也说得很清楚:MyBatsi官方文档 。

      官方文档里写了有四种方式来指定xml映射文件的位置:类路径相对资源引用(resource),完全限定的url引用(包括file:/// URL),类名或包名,下面分别举个例子:

    <mappers>
        <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
    
        <mapper url="file:///var/mappers/AuthorMapper.xml"/>
    
        <mapper class="org.mybatis.builder.AuthorMapper"/>
    
        <package name="org.mybatis.builder"/>
    
    </mappers>

      然而,根据这位朋友(Hern)的文章(参考出处),这四种指定方式有一定的限制:

    1、当采用class、package方式时,映射文件(Mapper.xml)和接口必须命名相同,并且放在与接口同一目录下。(尽量不要采用这种方法)

    2、当采用class方式时,没有SQL映射文件,所有的SQL都是利用注解写在接口上,这样就可以避免注意1的事情发生,提高维护性,不是很重要的SQL语句可以采用注解的方式,这样可以提高开发速度,重要和复杂的接口、SQL建议还是采用SQL映射文件的方式。(尽量采用这种方法)

      我什么会搜到这位朋友的文章呢?因为我自己有个问题一直没解决。

      以前一般都是用resource指定xml文件的位置,不论有多少个xml文件,都在<mappers>里一个个写出来,因为我找不到可以批量指定的方法(通配符什么的试了,没成功)(注意别忘了现在的背景是mapper接口和xml映射文件在不同的目录下)。

      Hern的文章提醒了我,可以指定一个Package来批量加载XML映射文件,但是它们必须和mapper接口在同一目录下。如果是这样,那我们又回到了上第一种情况——必须解决掉IDEA下Maven工程默认不会对src/main/java的非.java文件的行为。这样做好像也不错,也就是可以不需要批量指定,只要配置了Maven节点,mapper接口同目录下的xml映射文件就能自动加载了。

      所以现在的问题就变成了:必须在XML文件与mapper接口在不同目录下的情况下找到批量加载XML映射文件的方法。

      还真的找到了,StackOverflow(How to load mapper xml files with wildcard?)给了启发。

      方法就是在applicationContext-dao.xml注册SqlSessionFactory的bean时,设置一个"mapperLocation"属性(property),来告诉MyBatis那些XML映射文件的位置(可以使用通配符),如下:

    <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 数据库连接池 -->
            <property name="dataSource" ref="dataSource" />
            <!-- 加载mybatis的全局配置文件 -->
            <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
    <!--批量指定mapper的xml文件的方法,此时xml无需与接口在同一个文件夹下--> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"/> </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.taotao.mapper" /> </bean>

      也就是说,在同一个地方,创建了SqlSessionFactory的Bean,批量加载了XML映射文件,创建了所有mapper接口的Bean。这样做,我的MyBatis核心配置文件就仍然可以保持0配置。

       然后我也查看了SqlSessionFactoryBean的官方文档,这个类中的确有这么一个方法:

    void setMapperLocations(Resource[] mapperLocations)

     Set locations of MyBatis mapper files that are going to be merged into the SqlSessionFactory configuration at runtime.This is an alternative to specifying "<sqlmapper>" entries in an MyBatis config file. This property being based on Spring's resource abstraction also allows for specifying resource patterns here: e.g. "classpath*:sqlmap/*-mapper.xml".

    设置将在运行时合并到SqlSessionFactory配置中的MyBatis映射器文件的位置。 这是在MyBatis配置文件中指定“<sqlmapper>”条目的替代方法。 此属性基于Spring的资源抽象,也允许在此指定资源模式,例如: "classpath*:sqlmap/*-mapper.xml"

       还能再说什么呢,Spring牛逼就完事了!!

      这个应该是最佳解决方案了,ok,任务完成~

  • 相关阅读:
    Quicksum -SilverN
    uva 140 bandwidth (好题) ——yhx
    uva 129 krypton factors ——yhx
    uva 524 prime ring problem——yhx
    uva 10976 fractions again(水题)——yhx
    uva 11059 maximum product(水题)——yhx
    uva 725 division(水题)——yhx
    uva 11853 paintball(好题)——yhx
    uva 1599 ideal path(好题)——yhx
    uva 1572 self-assembly ——yhx
  • 原文地址:https://www.cnblogs.com/bigbigbigo/p/11020695.html
Copyright © 2011-2022 走看看