前面在 MyBatis 快速入门篇中,我们使用了 MyBatis 原生的开发方式操作数据库,解决了 JDBC 操作数据库时的硬编码和操作繁琐的问题。实际上,在 Java 项目中,我们更常用的是 Mapper 代理开发的方式。
两种方式有什么不同呢?
前面在使用基本方式操作数据库时,我们使用 sqlSession 原生的方法 selectList 执行 sql 语句并处理结果集对象。示例:
List<Student> students = sqlSession.selectList("test.selectAll"); //参数是一个字符串,该字符串必须是映射配置文件的 namespace.id
该方法的参数必须是 sql 映射配置文件的 name.id
,并且是以字符串的方式传递给该方法,于是这里又出现了硬编码的问题,而且这里使用 id 的方式也不是一种方便的设计,因为我们在编码时还需要在对应的映射配置文件中寻找 id,于是出现了 Mapper 代理开发的方式来解决这个问题。
在使用 Mapper 代理开发方式操作数据库时,通过 SqlSession 类对象获取一个指定 Mapper 接口的 Mapper 代理对象,使用该代理对象就可以调用对应 Mapper 接口中的方法,而这个方法就与映射配置文件中的 id 对应,从而找到了 sql 并执行,最后处理结果集对象。示例:
//3. 执行sql
//3.1 获取StudentMapper接口的代理对象
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.selectAll();
总的来说,Mapper 代理方式具有以下两个优点:
从上面的例子中不难看出,使用 Mapper 代理的方式具有更多的优势,首先他不依赖于字符串的字面值,会更加的方便和安全。其次,如果你的 IDE 有代码自动补全的功能,那么它可以帮你快速的是选择映射文件的 sql 语句,而不依赖于对应的 id。
使用 Mapper 代理开发的方式,必须执行以下几个步骤:
下面通过案例了解 Mapper 代理开发的方式的过程,案例依然是使用入门篇中的查询学生信息,并封装为对象,存放在集合中。
第一步:
在 org.chengzi.mapper
包下创建 StudentMapper,示例:
public interface StudentMapper {
List<Student> selectAll();
Student selectById(int id);
}
在 resources 下创建 org / chengzi / mapper
目录,并在该文件目录下创建 StudentMapper.xml 配置文件。这样做保证了 Mapper 接口和 sql 映射配置文件在同一文件目录下。
第二步:设置 sql 映射文件的 namespace 属性和 Mapper 接口的全限定名一致。示例:
<!--
namespace:名称空间。必须是对应接口的全限定名
-->
<mapper namespace="org.chengzi.mapper.StudentMapper">
<select id="selectAll" resultType="org.chengzi.pojo.User">
select *
from student;
</select>
</mapper>
第三步:在 MyBatis 核心配置文件中加载 sql 映射配置文件,示例:
<mappers>
<!--加载sql映射文件-->
<mapper resource="org/chengzi/mapper/StudentMapper.xml"/>
</mappers>
注意:后面两步使用
/
作为文件路径分隔符
完成上面三步我们就可以编写测试代码来操作数据库,完成相关操作。示例:
public class MyBatisDemo2 {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 执行sql
//3.1 获取StudentMapper接口的代理对象
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.selectAll();
System.out.println(students);
//4. 释放资源
sqlSession.close();
}
}
运行结果:
不同于 MyBatis 的基本方法,这里我们通过 sqlSession 对象对应的方法获取了 StudentMapper 接口的代理对象,使用该代理对象执行 sql 语句,封装结果集对象。返回代理对象的过程由MyBatis内部完成。
小 tips:在 MyBatis 核心配置文件中加载 sql 映射配置文件时,如果 sql 映射配置文件数量较多时,这个步骤也是比较麻烦的,MyBatis 也提供了解决这个问题的方法。
如果 Mapper 接口名称和 sql 映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化 sql 映射文件的加载,只需要在核心配置文件中将加载 sql 映射配置文件的部分修改为:
<mappers>
<package name="org.chengzi.mapper"/>
mappers>
在使用 Mapper 代理开发时,我们通过 SqlSessionFactory 类的 openSession() 方法获取了 SqlSession 类对象,接着通过 SqlSession 类对象获取指定 Mapper接口的 Mapper 代理对象。
在获取 Mapper 代理对象时,我们可以找到对应的 Mapper 接口,在同一个目录下可以找到对应的与该接口同名的 sql 映射文件。使用代理对象调用对应Mapper接口中的方法,该方法对应着 sql映射配置文件中的 id 属性,通过 id 属性可以找到 对应的 sql 语句,进而执行了sql语句并封装结果集对象。
例如在上面案例中,studentMapper
代理对象执行了 selectAll() 方法,返回 List 对象,其实其底层还是执行了下面的语句:
List<User> users = sqlSession.selectList("test.selectAll");
使用 MyBatis 原生方式开发,部分过程依赖于字符串常量值,存在硬编码的问题,同时使用命令空间和 sql 唯一标识作为执行 sql 的参数,在编写代码时比较麻烦。使用 Mapper 代理的方式具有更多的优势,首先他不依赖于字符串的字面值,会更加的方便和安全。其次,如果你的 IDE 有代码自动补全的功能,那么它可以帮你快速的是选择映射文件的 sql 语句,而不依赖于对应的 id。