在前一章节,我们对自定义持久层框架有了一个基本的思路,接下来我们主要就是需要完成自定义持久层级框架的编写
首先我们先来编写使用端代码,新建一个maven项目,maven项目中pom.xml文件内容如下
4.0.0
study.lagou.com
persistence-test
1.0-SNAPSHOT
UTF-8
UTF-8
1.8
1.8
1.8
在项目的resources文件夹下创建sqlMapConfig.xml配置文件
接着创建mapper.xml配置文件,但是我们在创建之前,先思考一个问题,在我们的一个项目当中,是不是应该会有很多个模块,不可能只有一个模块,可能有用户、商品、订单等等模块,如果我们只有一个mapper.xml文件话,所有的SQL语句都要写到这一个mapper.xml文件当中,这样做好吗?如果所有的SQL语句都写到一个mapper.xml文件,对于我们的操作和编写都是非常麻烦的,而且不易于阅读,为了使我们的mapper.xml文件当中的内容不至于太长,容易阅读和维护,所以我们推荐按照模块分别编写mapper.xml文件
接下来我们就按照不同的模块来编写不同的映射配置文件,比如当前我们有一个用户模块和商品模块,那么我们则需要编写两个映射配置文件
一个是UserMapper.xml,这个映射配置文件只用来编写用户相关的SQL语句
另外一个是ProduceMapper.xml,这个一配置文件只用来编写商品相关的SQL语句
接下来我们先以UserMapper.xml的编写来一步步演示,具体编写mapper.xml文件时需要注意的问题
简单的编写完以上的UserMapper.xml文件,我们可以看到在我们UserMapper.xml文件中有两条SQL语句,那么我们如何能够定位到映射配置文件中这两条SQL语句呢(具体调用时如何区分应该调用哪一条),如何区分是查询所有还是查询单个?我们无法区分,所以我们考虑给每一个SQL语句给一个标识属性(id),有了以下改进版本
如此改进完成之后,我们则可以通过selectList、和selectOne定位到具体我们需要的是哪一条SQL语句了,接着思考,我们改进完成之后还有没有其它问题呢?
如果是项目当中只有这一个模块,是没有问题的,但是如果项目当中还存在其它模块,其它模块也是这么编写的呢?我们以ProduceMapper.xml来举例说明
ProduceMapper.xml文件中也是这么写的,取的标识名也是selectList和selectOne,只是查询的表名不一样,现在通过selectList和selectOne这两个标识还能定位到唯一一条SQL语句吗?因为selectList和selectOne在项目当中存在多个了,我们不能区分开来,所以我需要再加一层标识加以识别处理==>命名空间namespace
现在我们可以约定,SQL的唯一标识,可以由namespace+"."+id来组成,这样就能唯一标识出唯一一条SQL语句了,由namespace.id组合成的唯一标识,我们将它称之为statementId
接着往下分析,现在我们能够获取到唯一一条SQL语句进行执行,但是执行完成后,返回的结果集还是需要我们手动去解析放到到具体的对象属性当中,这个手动封装返回结果集的过程较为繁琐,我需要借助于反射、内省等机制,完成返回结果集与对象属性的自动解析和封装,那么我们必须获取到对应对象的全路径才能够做操作,所以我们还需要给有返回结果集的查询语句,添加resultType属性,将返回对象的全路径放置进去,我们才能通过反射、内省等技术进行操作处理
至此,对selectList方法,我们能够完成基本的操作,但是我们接着看selectOne方法,在执行selectOne方法的时候,我们需要传入参数,才能够构建查询的SQL语句,所以在selectOne方法上我们还得添加paramterType属性,而针对多个参数的传递,还是得基于面向对象的思想进行传递,所以接下来我们再对selectOne方法进行完善
将参数对象通过paramterType属性给到自定义持久层框架,持久层框架需要做的就是通过反射,取到参数对象的属性值,取到对应的属性值之后,我们要给对应的占位符进行赋值,但是我们怎么定位到将哪个属性值赋值到哪一个占位符上面呢?显然,我们通过以“?”做为占位符的方法,无法完成对应,所以我们需要对占位符进行改进,改进成#{属性}的方式来进行处理,注意:#{}当中的属性,需要与paramterType属性对象中的属性一一对应才行,不能随便给!
我们在占位符中给的是id和username两个属性,那么paramterType对应对象中一定存在这两个属性值
package study.lagou.com.persistence.test.pojo;
/**
* @Description: 功能描述
* @Author houjh
* @Email: [email protected]
* @Date: 2021-1-27 22:13
*/
public class User {
/**
* 主键信息
*/
private Integer id;
/**
* 用户名称
*/
private String username;
/**
* 用户密码
*/
private String password;
/**
* 用户昵称
*/
private String nickname;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
至此,我们编写映射配置文件算是基本上完成了,但是上一节当中,我们在分析自定义持久层框架思路的时候,分析出自定义持久层框架的第一步就是加载配置文件,我们没有必要通过getResourceAsStream(String path)方法对配置文件加载两次,而是直接在sqlMapConfig.xml存放一份映射配置文件的全路径,后面通过解析sqlMapConfig.xml文件就可以获取到mapper.xml映射配置文件的全路径,对mapper文件进行操作,所以我们再对sqlMapConfig.xml配置文件进行完善
至此,我们使用端代码编写完成
具体代码对应下载地址:https://gitee.com/happymima/mybatis.git