之前写的一个自己实现一个简单的mybatis但是不想写文档了。。。。。
前言
暑假小学期要完了,作业是用Java实现对MySQL的CUDR,不让用Mybatis。
经过努力奋战之后········
我把以前做的改了个名交了,然后脑子一抽,不让用mybatis,那我自己写一个拿来用没问题吧。
经过广泛参考网上的教程,已经实现的简单的注解查询,其他还在慢慢磨
主要参考了这几个大佬的博客
浅析MyBatis(二):手写一个自己的MyBatis简单框架 - Chiakiiii - 博客园 (cnblogs.com)
自己实现一个 MyBatis 框架 - 当年明月123 - 博客园 (cnblogs.com)
还有mybatis中文网 MyBatis的工作原理以及核心流程介绍 - MyBatis中文官网
建议去看这两个大佬的博客
我一开始只是简单写了一个流程理顺一下思路
后来想着,写都写了,就发出来吧,真要学习或者参考建议去大佬的博客,页面比我的好看,代码写的比我好,说的还比我清楚
我是废物,唉
Mybatis的核心流程(这里来源mybatis中文网)
流程图

流程详解
mybatis中文网的解释
(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。
(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。
(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。
(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。
(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。
(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。
我的理解
读取资源文件 对应 1、2
读取连接数据库的配置文件、还有有sql语句的mapper.xml或者mapper.Java等资源配置文件
反应在我写的代码里就是在这一步的时候,连接数据库用的账户、密码url等还有各个mapper的sql语句对应的返回参数的类型已经存储在了一个名为Configuration的对象中
建立与数据库的连接 对应 3
通过Configuration对象中的配置信息建立一个与数据库的连接
应该是创建mapper对象(Mapper mapper = <>)
代码实现
依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
两个pojo类
MappedStatement
这里我偷懒使用了lombok,其实应该是没有params这个的,但限于我对Java的了解,不知道怎么处理多个参数,就加了一个
import lombok.Data;
@Data
public class MappedStatement {
//sql语句
private String queryStr;
//返回类型
private String resultType;
//参数(我自己加的)
private String params[];
}
Configuration
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class Configuration {
//数据库驱动
private String driver;
//数据库链接
private String url;
//用户名
private String username;
//密码
private String password;
//所有的mapper文件内的sql语句以及对应函数等
private Map<String, MappedStatement>mappers=new HashMap<>();
}
第一步读取资源文件
数据库配置文件
这里我用的是json格式,因为我xml基本没有怎么用过,所以使用的json格式
这里的格式自己怎么喜欢怎么来就行,反正最后都是对应到Configuration这个类
config.json
这里的命名非必须的记得与自己对应就行
{
"propertyElement": {
"user":"xxxx",
"password":"xxxx",
"driverClass":"xxxx",
"jdbcUrl":"xxxx"
},
"mapperElement": [
{"class": "com.test.Mapper"},
{"class": "mapper文件的地址"}
]
}
返回Configuration对象
这里用到了两个函数
parse函数是用来读取json文件返回数据库配置的
parseMapperAnnotation函数是读取mapper文件(我写的代码只支持注解,不支持xml文件)
返回的是 Map<String, MappedStatement>mappers
当然还有一个额外的用来读取参数的getMethodParameterNamesByAnnotation
ConfigBuilder
import Mymybatis.cudr.*;
import Mymybatis.pojo.Configuration;
import Mymybatis.pojo.MappedStatement;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
public class ConfigBuilder {
/**
* 读取数据库配置文件
*
* @param inputStream json文件的文件流
* @return configuration对象
*/
public static Configuration parse(InputStream inputStream) throws ClassNotFoundException {
String jsonStr = "";
try {
Reader reader = new InputStreamReader(inputStream,"utf-8");
int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
reader.close();
jsonStr = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
JSONObject jsonObject = JSON.parseObject(jsonStr);
JSONObject configObject = JSON.parseObject(jsonObject.getString("propertyElement"));
Configuration configuration = new Configuration();
configuration.setUsername(configObject.getString("user"));
configuration.setPassword(configObject.getString("password"));
configuration.setUrl(configObject.getString("jdbcUrl"));
configuration.setDriver(configObject.getString("driverClass"));
JSONArray mappers =JSON.parseArray(jsonObject.getString("mapperElement"));
for (int i = 0; i < mappers.size(); i++) {
JSONObject mapperobject = (JSONObject) mappers.get(i);
Map<String, MappedStatement>map=parseMapperAnnotation(mapperobject.getString("class"));
configuration.setMappers(map);
}
return configuration;
}
/**
* 获取指定方法的参数名
*
* @param method 要获取参数名的方法
* @return 按参数顺序排列的参数名列表
*/
public static String[] getMethodParameterNamesByAnnotation(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations == null || parameterAnnotations.length == 0) {
return null;
}
String[] parameterNames = new String[parameterAnnotations.length];
int i = 0;
for (Annotation[] parameterAnnotation : parameterAnnotations) {
for (Annotation annotation : parameterAnnotation) {
if (annotation instanceof Param) {
Param param = (Param) annotation;
parameterNames[i++] = param.value();
}
}
}
return parameterNames;
}
/**
* 读取mapper文件封装成集合
*
* @param mapperClassPath mapper文件的路径
* @return Map<String, MappedStatement>mappers
* String -> mapper文件名+‘.’+函数名
* MappedStatement 对应sql语句+返回类型+参数
*/
private static Map<String, MappedStatement>parseMapperAnnotation(String mapperClassPath) throws ClassNotFoundException {
Map<String,MappedStatement>mappers =new HashMap<>();
//获取mapper接口对应的class对象
Class<?> mapperclass =Class.forName(mapperClassPath);
//获取class对象中的函数
Method[] methods = mapperclass.getMethods();
//遍历Method数组对相关注解进行解析
for (Method method : methods) {
if (method.isAnnotationPresent(Insert.class)){
MappedStatement mappedStatement=new MappedStatement();
Insert insertAnnotation = method.getAnnotation(Insert.class);
//获取参数+设置参数
mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
//获取注解中的value,也就是中的@Insert("sql语句这一部分")
String queryString = insertAnnotation.value();
mappedStatement.setQueryStr(queryString);
//获取当前函数的返回值以及泛型
Type type = method.getGenericReturnType();
//校验
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[]types=parameterizedType.getActualTypeArguments();
Class<?>clazz= (Class<?>) types[0];
String resultType=clazz.getName();
mappedStatement.setResultType(resultType);
}
//给key赋值 Map<String,MapperStatement>mappers
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className+"."+methodName;
mappers.put(key,mappedStatement);
}
if (method.isAnnotationPresent(Select.class)){
MappedStatement mappedStatement=new MappedStatement();
Select selectAnnotation = method.getAnnotation(Select.class);
mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
String queryString = selectAnnotation.value();
mappedStatement.setQueryStr(queryString);
Type type = method.getGenericReturnType();
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[]types=parameterizedType.getActualTypeArguments();
Class<?>clazz= (Class<?>) types[0];
String resultType=clazz.getName();
mappedStatement.setResultType(resultType);
}
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className+"."+methodName;
mappers.put(key,mappedStatement);
}
if (method.isAnnotationPresent(Delete.class)){
MappedStatement mappedStatement=new MappedStatement();
Delete deleteAnnotation = method.getAnnotation(Delete.class);
mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
String queryString = deleteAnnotation.value();
mappedStatement.setQueryStr(queryString);
Type type = method.getGenericReturnType();
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[]types=parameterizedType.getActualTypeArguments();
Class<?>clazz= (Class<?>) types[0];
String resultType=clazz.getName();
mappedStatement.setResultType(resultType);
}
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className+"."+methodName;
mappers.put(key,mappedStatement);
}
if (method.isAnnotationPresent(Update.class)){
MappedStatement mappedStatement=new MappedStatement();
Update updateAnnotation = method.getAnnotation(Update.class);
mappedStatement.setParams(getMethodParameterNamesByAnnotation(method));
String queryString = updateAnnotation.value();
mappedStatement.setQueryStr(queryString);
Type type = method.getGenericReturnType();
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[]types=parameterizedType.getActualTypeArguments();
Class<?>clazz= (Class<?>) types[0];
String resultType=clazz.getName();
mappedStatement.setResultType(resultType);
}
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className+"."+methodName;
mappers.put(key,mappedStatement);
}
}
return mappers;
}
public static void main(String[] args) throws ClassNotFoundException {
// parse();
}
}
我写的源码链接
我记得当时写完测试是可以用的
https://gitee.com/october_Wr/study-notes/tree/master/一些备份/MyMybatis/Mymybatis

浙公网安备 33010602011771号