MyBatis 动态代理开发的理解

发布于 2023-10-14 11:33:33 字数 7807 浏览 29 评论 0

通常情况下,我们 Mapper 接口和对应的映射配置文件是放在同一个包中的,但是事实真的是这样吗?难道 Mapper 接口和映射配置文件就一定要放在一起吗?

MyBatis 非动态代理开发

在日常开发中我们或许都使用动态代理的方式,但是动态代理开发并不是 MyBatis 最基本的开发模式:

传统开发流程

第一步:在 resource/ 目录下新建 SqlMapConfig.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>
	<environments default="development">
		<environment>
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:  mysql://localhost:3306/test"/>
				<property name="username" value="root"/>
				<property name="password" value="980613"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="com/tjd/mapper/UserMapper.xml"></mapper>
	</mappers>
</configuration>

第二步:在 com.tjd.mapper 包下创建映射文件:

<?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.tjd.mapper.UserMapper">
    <select resultType="com.tjd.pojo.User" parameterType="long">
        select * from user where uid = #{id}
    </select>
    <select resultType="com.tjd.pojo.User" parameterType="string" >
        select * from user where uname = #{name}
    </select>
</mapper>

走到这一步,MyBatis 环境就搭建完成了,此时我们就需要开始进行数据库操作:

第三步:使用 MyBatis 提供的 API 进行数据库操作

public class MyBatisTest {
    @Test
    public void test() throws IOException {
        InputStream resource = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resource);
        SqlSession session = sessionFactory.openSession();
        Object o = session.selectOne("com.tjd.mapper.UserMapper.getUserById",1L);
    }
}

理解传统开发流程

​ 在非动态代理开发时,并不需要写什么 Mapper 接口,只需要配置映射文件,然后获取的 SqlSeesion 对象,通过该对象的 selectOne 或 selectList 方法进行数据库查询即可,而这些方法只需要传入 SQL 语句的 ID 即可执行相应的 SQL 语句,然后将结果映射为实体类。(注:通常我们会在 ID 前面加上映射文件的 namespace,但是如果 ID 没有重复的情况下,是可以直接通过 ID 调用 SQL 语句)。

需要注意的是,不进行动态代理开发时,在 SqlMapConfig 文件中只能使用<mapper resource>或<mapper url>进行映射文件的加载 。而由于使用 resource 指定的映射文件位置,所以映射文件实际上放在哪都无所谓,只要 resource 指向映射文件即可。

​ 通常在这种开发模式中,我们仍然会创建 Dao 层代码,对数据库操作进行封装,但是其本质并没有变,就是 MyBatis 框架将映射文件的 SQL 语句加载进系统,然后通过获取的 SqlSession 对象执行指定的 SQL 语句,所以 在这种开发模式中,映射配置文件的位置、文件名、namespace、statement_id 的填写格式并没有强制要求,唯一的要求就是每一个 namespace+id 可以唯一定位一个 SQL 语句

MyBatis 动态代理开发

在传统开发中,我们需要指定映射文件配置的 SQL 语句的 ID 才能执行 SQL 语句:

User user = (User)session.selectOne("com.tjd.mapper.UserMapper.getUserById",1L); 

诚然,这种方式能够正常工作,并且对于使用旧版本 MyBatis 的用户来说也比较熟悉。不过现在有了一种更简洁的方式 ——动态代理开发,这种开发模式不仅可以执行更清晰和类型安全的代码,而且还不用担心易错的字符串字面值以及强制类型转换。

动态代理开发流程

第一步:创建 Mapper 接口

但是如果想要进行动态代理开发就需要满足动态代理开发的要求了,在传统开发模式中有没有 Mapper 接口都无所谓,但是由于采用的是动态代理开发,所以必须要一个接口:

package com.tjd.mapper;
public interface UserMapper {
    User getUserById(Long id);
    User getUserByName(String name);
}

第二步:创建映射配置文件

<?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.tjd.mapper.UserMapper">
    <select resultType="com.tjd.pojo.User" parameterType="long">
        select * from user where uid = #{id}
    </select>
    <select resultType="com.tjd.pojo.User" parameterType="string">
        select * from user where uname = #{name}
    </select>
</mapper>

使用动态代理开发时,映射文件的 namespace 必须是 Mapper 接口的全限定类名,而 SQL 语句的 ID 必须与接口中的方法名一一对应 。但是映射文件名和映射文件的位置并没有强制要求,具体细节在后面讲解。

第三步:配置 MyBatis 核心配置文件

<?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>

	<settings>
		<setting name="logImpl" value="STDOUT_LOGGING" />
	</settings>
	<typeAliases>
		<package name="com.tjd.spring_mybatis_plus.pojo"/>
	</typeAliases>

	<environments default="development">
		<environment>
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:  mysql://localhost:3306/test"/>
				<property name="username" value="root"/>
				<property name="password" value="980613"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="com/tjd/spring_mybatis_plus/mapper/UserMapper.xml"></mapper>
		<!--<mapper class="com.tjd.spring_mybatis_plus.mapper.UserMapper"></mapper>-->
	</mappers>
</configuration>

在使用动态代理开发时,指定映射文件位置可以有四种模式: <mapper resource>、<mapper url>、<mapper class>、<package> ,但是这四种配置模式对映射文件名和映射文件位置有着不同的影响,具体来说:

  • 在使用 <mapper resource>、<mapper url> 时,映射文件可以放在任意地方,映射文件名可以任意取;
  • 在使用 <mapper class><package> 时,映射文件必须与 Mapper 接口处于相同的包中,并且映射文件名和接口名相同。

第四步:获取代理对象执行数据库操作

public class MyBatisTest {
    @Test
    public void test() throws IOException {
        InputStream resource = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resource);
        SqlSession session = sessionFactory.openSession();
        //获取代理对象
        UserMapper mapper = session.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1L);
    }
}

理解 MyBatis 动态代理开发

​ 虽说是动态代理开发,但是实质的原理非常简单,就是 MyBatis 生成代理对象,在代理对象的方法中,会自动根据当前执行的方法名,然后定位到映射配置文件中配置的 SQL 语句。这就避免了我们使用字符串常量来调用 SQL 语句了,也避免了最后结果的强制类型转换。

​ 在这种开发模式中,对映射配置文件有相应的要求:

  • Mapper 接口方法名和 Mapper.xml 中定义的 SQL 语句的 ID 一一对应。
  • 映射配置文件的 namespace 与接口的全限定类名相同。
  • Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同。
  • Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同。

但是对于映射配置文件位置和文件名的要求,取决于采用哪种模式加载配置文件(resource、url、class、package)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

内心激荡

文章 0 评论 0

JSmiles

文章 0 评论 0

左秋

文章 0 评论 0

迪街小绵羊

文章 0 评论 0

瞳孔里扚悲伤

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文