mappers 映射器的两种映射方案:
要定义 SQL 映射语句先要告诉 MyBatis 到哪里去找到这些语句。 Java 在这方面没有提供一个很好的方法, 所以最佳的方式是用mappers 映射器告诉 MyBatis 到哪里去找映射文件。mappers 映射器提供了两种映射方案,一是直接指定相应的mapper .xml文件,二是指定与mapper .xml相关联的接口。例如:
<mappers>
<!--指定mapper.xml的相对路径-->
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<!--指定mapper.xml的绝对路径-->
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<mappers>
<!--指定相关联的接口的全限定路径-->
<mapper class="org.mybatis.builder.AuthorMapper"/>
<!--指定包下所有相关联的接口-->
<package name="org.mybatis.builder"/>
</mappers>
前面所述俱是用的第一种方案,第一种方案适用于传统的DAO封装。下面介绍一下第二种方案,第二种方案才是Mybatis推荐的方案,因为它具有很多优点,其中最显著的优点在于:
- 调用sql命令时,直接调用接口中的方法,由程序内部自动关联mapper.xml文件中对应的sql命令,因此不用再写冗长的namespace;
- 在第一种方案中,调用sql命令时只能传入一个参数,如果要传入多个参数还得用对象或集合将其封装,而第二种方案中由于调用的是接口中声明的方法,既然是方法那么就可以传入多个参数。
但是第二种方案有以下两个要求:
- 接口和映射文件必须在同一个包中;
- 接口和映射文件除去文件后缀其文件名必须相同。
第二种方案适用于动态代理DAO开发,是Mybatis推荐的方案,动态代理对接口和映射文件也有几个要求:
- 接口中声明的方法名必须和映射文件中对应的sql的id一致;
- 接口中声明的方法参数必须和映射文件中对应的sql的parameterType一致;
- 接口中声明的方法返回值必须和映射文件中对应的sql的resultType一致。
例:
1、在MySQl中建表,在相应的web项目的src目录下,新建包与实体类:
此处用上一篇博客的flower表,包名“cn.jingpengchong.pojo”及包下的Flower.java
2、在src目录下,新建包与mapper.xml文件:
包名“cn.jingpengchong.mapper”,文件“FlowerMapper.xml”文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.jingpengchong.mapper.FlowerMapper">
<!-- 根据价格和产地查找花 -->
<select id="selByPriPro" resultType="flower">
<!-- 用#{0}/#{param1}接收第一个参数,用#{1}/#{param2}接收第一个参数 -->
select * from flower where price = #{0} and production = #{1}
</select>
</mapper>
3、在src目录下,新建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>
<!--给Flower类设置别名,这样在声明该类类型时直接写“Flower”或“flower”即可-->
<typeAliases>
<package name="cn.jingpengchong.pojo"/>
</typeAliases>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--将该包下文件名相同的接口的方法和xml文件的sql命令一一关联起来-->
<package name="cn.jingpengchong.mapper"/>
</mappers>
</configuration>
4、在mapper.xml文件所在包下新建接口,接口名要与对应的mapper.xml文件名相同:
在包“cn.jingpengchong.mapper”下新建接口“FlowerMapper.java”:
package cn.jingpengchong.mapper;
import java.util.List;
import cn.jingpengchong.pojo.Flower;
public interface FlowerMapper {
/**
* 根据价格和产地查询花
* selByPriPro:方法名要与对应xml文件中对应方法的id相同
* pri:价格price
* pro:产地production
*/
List<Flower> selByPriPro(double pri, String pro);
}
5、新建测试类:
这里在“cn.jingpengchong.test”包下新建了一个“Test.java”文件:
package cn.jingpengchong.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import cn.jingpengchong.mapper.FlowerMapper;
import cn.jingpengchong.pojo.Flower;
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
FlowerMapper mapper = session.getMapper(FlowerMapper.class);
List<Flower> list = mapper.selByPriPro(4, "南美阿根廷");
for (Flower flower : list) {
System.out.println(flower);
}
}
}
运行结果如下:
附:mapper.xml文件中SQL命令的参数接收
1、#{0}、#{1}、#{2}…:用于获取第1、2、3…个参数;
2、#{param1}、#{param2}、#{param3}…:用于获取第1、2、3…个参数;
3、上面的#{}不能换成${},因为除了获取Map集合中的元素或对象中的属性值,${}中的内容都会被sql简单的作为字符串拼接;
4、可以用“@Param()”注解将参数封装成Map集合,如果想要用下面的方法获取参数:
<select id="selByPriPro" resultType="flower">
select * from flower where price = #{price} and production = #{production}
</select>
那么接口中声明的方法应该加上对应的注解:
List<Flower> selByPriPro(@Param("price") double pri, @Param("production") String pro);
修改完毕运行测试类仍然正确,结果如下:
这种方式是将注解中传入的参数作为key,将后面的参数作为value封装成了一个Map集合传给了mapper.xml文件,但即便如此,把#{}换成${}仍然会出错:
可以在日志中看到接收字符串参数时单/双引号丢失了,这也是在开发中用#{},而不用${}的原因!