MyBatis mapper
1. 前言
本小节,我们将一起学习 MyBatis mapper。
在上一节中我们以 JDBC 的方式使用了 MyBatis,但在实际应用中是不会选择这种方式来执行 SQL 的,MyBatis提供了 mapper 这种优雅且易维护
的方式来帮助我们更好地去使用 SQL。
2. 定义
慕课解释:mapper 是 Java 方法和 SQL 语句之间的
桥梁
。
Java 接口方法与 SQL 语句以及 mapper 之间的关系如下图所示:
3. 新建 mapper
mapper 只是一个抽象的概念
,它其实就是 Java 里面的一个接口类,我们不需要实现这个接口类,MyBatis 会通过动态代理自动帮我们执行接口方法所对应的 SQL 语句。
接下来,我们以UserMapper
为例,来看一看 mapper 究竟是如何定义和组成的。
首先,在 com.imooc.mybatis 包下新建 mapper
包,并在 mapper 包下新建接口类UserMapper.java
。如下:
package com.imooc.mybatis.mapper;
public interface UserMapper {
}
MyBatis 提供了注解
和XML
两种方式来连接接口方法和 SQL 语句。
3.1 注解方式
我们为 UserMapper 添加一个方法selectUsernameById
,该方法的作用为通过用户 id 查询用户名称,如下:
package com.imooc.mybatis.mapper;
public interface UserMapper {
String selectUsernameById(Integer id);
}
selectUsernameById 方法接受 id 参数(用户 id),返回用户名称(String 类型)。
有了方法定义后,我们再通过注解为该方法添加上对应的 SQL 语句:
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT username FROM imooc_user WHERE id = #{id}")
String selectUsernameById(Integer id);
}
Select
注解对应 SQL 的 select 查询,注解中的语句就是相应的 SQL 语句,当然这并非真实的 SQL 语句,具体的差异性我们后续章节再说。
3.2 XML 方式
XML 方式是更加强大和易用的一种方式,虽然它没有注解那么方便,但是功能更强、更易维护,是 MyBatis 官方推荐的一种方式。
在 mapper 包中,我们新建另一个文件UserMapper.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="com.imooc.mybatis.mapper.UserMapper">
</mapper>
mapper
标签对应一个 mapper 接口类,这里应该对应 UserMapper,所以在 mapper 标签里面我们还需要加上 namespace 这个属性,它的值为 UserMapper 的类全路径,这样 UserMapper.xml 配置文件就与 UserMapper.java 对应起来了。
提示,namespace 命名空间是每一个 mapper 文件所独有的,它唯一标识着一个 mapper。
注意: 在这里,.xml 配置文件必须与其对应的接口在同一个包内。
二者在目录中的位置如下:
src/main/java/com/imooc/mybatis/mapper
├── UserMapper.java
└── UserMapper.xml
在 UserMapper 接口中,我们再新增一个方法selectUserAgeById
,该方法的作用是通过用户 id 查询用户年龄。如下:
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT username FROM imooc_user WHERE id = #{id}")
String selectUsernameById(Integer id);
Integer selectUserAgeById(Integer id);
}
与之对应的 xml 文件中,我们也需要添加上对应的 SQL 语句。如下:
<?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="com.imooc.mybatis.mapper.UserMapper">
<select resultType="java.lang.Integer">
SELECT age FROM imooc_user WHERE id = #{id}
</select>
</mapper>
在 mapper 标签中,我们新增了 select 标签,对应 SQL 中的 select 查询;select 标签中有两个必填属性,第一个是 id ,它对应接口的方法名,即 selectUserAgeById,通过它 MyBatis 才能将二者对应起来,第二个是 resultType,它对应 SQL 语句的返回类型,与接口方法的返回值相同,为 Integer 类型。
好了,注解和 XML 的两种方式的简单使用已经介绍完毕了,这里仍然有一个可以完善的点,我们可以为 UserMapper 类打上一个 Mapper
注解,虽然这个注解并不是必须的,但是增强了代码的可读性。如下:
// 省略
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
// 省略其它诸多代码
}
4. 使用 mapper
mapper 定义好以后,我们接下来会介绍如何使用它。在上一节中,我们介绍了 MyBatis 配置式的简单使用,那么使用 mapper 其实很简单,只需在配置式使用的基础上增加几处配置和代码就行了。
4.1 mapper 配置
首先,我们需要在 mybatis-config.xml 配置文件中添加上对应的 mapper 配置:
<?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>
<environments default="development">
<environment>
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/imooc?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- mapper 对应的配置 -->
<mappers>
<mapper class="com.imooc.mybatis.mapper.UserMapper"/>
</mappers>
</configuration>
注意,mapper 可以有多个,对应的标签项应是 mappers,在 mappers 下面才有一个个的 mapper,如上面的 UserMapper;通过mapper 标签中的 class 属性,我们指定其对应的接口类,class 属性值为 UserMapper 的类全路径。
4.2 代码调用
有了配置以后,我们则可以在代码中调用 mapper 方法从而执行 SQL 得到结果了。在 pattern 包下,我们新建一个文件,名为StartWithMapper.java
,并向其中添加如下代码:
package com.imooc.mybatis.pattern;
import com.imooc.mybatis.mapper.UserMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
@SuppressWarnings({"Duplicates"})
public class StartWithMapper {
public static void main(String[] args) throws IOException, SQLException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
// 得到 mapper
UserMapper mapper = session.getMapper(UserMapper.class);
// 调用注解的SQL
String username = mapper.selectUsernameById(1);
System.out.println("username: " + username);
// 调用XML的SQL
Integer age = mapper.selectUserAgeById(1);
System.out.println("age: " + age);
// 关闭会话
session.close();
}
}
使用流程我们已经写在了代码注释中了,请务必阅读一下。
与上一节的区别在于,我们不再通过 session 得到连接从而执行 SQL 了,而是在 session 中得到配置好的 UserMapper,再通过调用UserMapper 的方法执行 SQL 从而得到结果。
执行这段代码,它会在控制台上打印如下信息(截取了部分重要信息):
13:13:50.104 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - ==> Preparing: SELECT username FROM imooc_user WHERE id = ?
13:13:50.205 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - ==> Parameters: 1(Integer)
13:13:50.344 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUsernameById - <== Total: 1
username: peter
13:13:50.351 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - ==> Preparing: SELECT age FROM imooc_user WHERE id = ?
13:13:50.351 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - ==> Parameters: 1(Integer)
13:13:50.354 [main] DEBUG com.imooc.mybatis.mapper.UserMapper.selectUserAgeById - <== Total: 1
age: 18
4.3 总结
从程序输出的信息中可以看出,UserMapper 的调用都成功了, 结合上一小节中 JDBC 的使用,可以清晰地感受到 MyBatis 完美的将 Java 对象与 SQL 语句分离,并通过 mapper 充当二者的桥梁,极大的提升了代码和 SQL 语句的维护性。
不同于原生 JDBC 的使用方式,MyBatis 会自动的通过 resultType 等配置来帮我们实现数据库类型到 Java 类型的转换,帮我们节省了大量的工作,当然 MyBatis 的功能远不止如此,我们将在后续的小节中一一揭晓。
5. 小结
- mapper 是 MyBatis 的核心概念,是 MyBatis
解耦
Java 对象与 SQL 语句的桥梁。 - MyBatis 官方文档中明确
强调
注解方式 SQL 无法发挥 MyBatis 的全部功能,但是可以方便地演示一些 demo。 - 如果单独使用 MyBatis,那么 mapper 接口必须和 .xml 配置文件在同一个包中,但是如果使用 spring 等工具就可以不必受此限制。