纯手写mybatis源码

本文将详述Mybatis框架的源码实现,从entity到mapper的映射过程,揭示其内部工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

entity:

package com.itmayiedu.entity;

public class User {

	private Integer id;
	private String userName;
	private Integer userAge;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Integer getUserAge() {
		return userAge;
	}

	public void setUserAge(Integer userAge) {
		this.userAge = userAge;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

}

mapper

package com.itmayiedu.mapper;

import java.util.List;

import com.itmayiedu.entity.User;
import com.itmayiedu.orm.annotation.ExtInsert;
import com.itmayiedu.orm.annotation.ExtParam;
import com.itmayiedu.orm.annotation.ExtSelect;

public interface UserMapper {

	@ExtInsert("insert into user(userName,userAge) values(#{userName},#{userAge})")
	public int insertUser(@ExtParam("userName") String userName, @ExtParam("userAge") Integer userAge);

	@ExtSelect("select * from User where userName=#{userName} and userAge=#{userAge} ")
	User selectUser(@ExtParam("userName") String name, @ExtParam("userAge") Integer userAge);

}

在这里插入图片描述
在这里插入图片描述

package com.itmayiedu.orm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义插入注解 <br>
 * 作者: 每特教育-余胜军<br>
 * 联系方式:QQ644064779|WWW.itmayiedu.com<br>
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExtInsert {
	String value();
}

package com.itmayiedu.orm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义参数注解<br>
 * 作者: 每特教育-余胜军<br>
 * 联系方式:QQ644064779|WWW.itmayiedu.com<br>
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ExtParam {
	String value();
}

package com.itmayiedu.orm.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExtSelect {

	String value();

}

在这里插入图片描述

package com.itmayiedu.orm.mybatis.aop;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import com.itmayiedu.orm.annotation.ExtInsert;
import com.itmayiedu.orm.annotation.ExtParam;
import com.itmayiedu.orm.annotation.ExtSelect;
import com.itmayiedu.orm.utils.JDBCUtils;
import com.itmayiedu.utils.SQLUtils;

/**
 * 使用反射动态代理技术 拦截接口防范 作者: 每特教育-余胜军<br>
 * 联系方式:QQ644064779|WWW.itmayiedu.com<br>
 */
public class MyInvocationHandlerMbatis implements InvocationHandler {
	private Object object;

	public MyInvocationHandlerMbatis(Object object) {
		this.object = object;
	}

	// proxy 代理对象 method拦截方法 args方法上的参数值
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("使用动态代理技术拦截接口方法开始");
		// 使用白话问翻译,@ExtInsert封装过程
		// 1. 判断方法上是否存在@ExtInsert
		ExtInsert extInsert = method.getDeclaredAnnotation(ExtInsert.class);
		if (extInsert != null) {
			return extInsert(extInsert, proxy, method, args);
		}
		// 2.查询的思路
		// 1. 判断方法上是否存 在注解
		ExtSelect extSelect = method.getDeclaredAnnotation(ExtSelect.class);
		if (extSelect != null) {
			// 2. 获取注解上查询的SQL语句
			String selectSQL = extSelect.value();
			// 3. 获取方法上的参数,绑定在一起
			ConcurrentHashMap<Object, Object> paramsMap = paramsMap(proxy, method, args);
			// 4. 参数替换?传递方式
			List<String> sqlSelectParameter = SQLUtils.sqlSelectParameter(selectSQL);
			// 5.传递参数
			List<Object> sqlParams = new ArrayList<>();
			for (String parameterName : sqlSelectParameter) {
				Object parameterValue = paramsMap.get(parameterName);
				sqlParams.add(parameterValue);
			}
			// 6.将sql语句替换成?
			String newSql = SQLUtils.parameQuestion(selectSQL, sqlSelectParameter);
			System.out.println("newSQL:" + newSql + ",sqlParams:" + sqlParams.toString());

			// 5.调用jdbc代码底层执行sql语句
			// 6.使用反射机制实例对象### 获取方法返回的类型,进行实例化
			// 思路:
			// 1.使用反射机制获取方法的类型
			// 2.判断是否有结果集,如果有结果集,在进行初始化
			// 3.使用反射机制,给对象赋值

			ResultSet res = JDBCUtils.query(newSql, sqlParams);
			// 判断是否存在值
			if (!res.next()) {
				return null;
			}
			// 下标往上移动移位
			res.previous();
			// 使用反射机制获取方法的类型
			Class<?> returnType = method.getReturnType();
			Object object = returnType.newInstance();
			while (res.next()) {
				// 获取当前所有的属性
				Field[] declaredFields = returnType.getDeclaredFields();
				for (Field field : declaredFields) {
					String fieldName = field.getName();
					Object fieldValue = res.getObject(fieldName);
					field.setAccessible(true);
					field.set(object, fieldValue);
				}
				// for (String parameteName : sqlSelectParameter) {
				// // 获取参数值
				// Object resultValue = res.getObject(parameteName);
				// // 使用java的反射值赋值
				// Field field = returnType.getDeclaredField(parameteName);
				// // 私有方法允许访问
				// field.setAccessible(true);
				// field.set(object, resultValue);
				// }
			}
			return object;
		}

		return null;
	}

	private Object extInsert(ExtInsert extInsert, Object proxy, Method method, Object[] args) {
		// 方法上存在@ExtInsert,获取他的SQL语句
		// 2. 获取SQL语句,获取注解Insert语句
		String insertSql = extInsert.value();
		// System.out.println("insertSql:" + insertSql);
		// 3. 获取方法的参数和SQL参数进行匹配
		// 定一个一个Map集合 KEY为@ExtParamValue,Value 结果为参数值
		ConcurrentHashMap<Object, Object> paramsMap = paramsMap(proxy, method, args);
		// 存放sql执行的参数---参数绑定过程
		String[] sqlInsertParameter = SQLUtils.sqlInsertParameter(insertSql);
		List<Object> sqlParams = sqlParams(sqlInsertParameter, paramsMap);
		// 4. 根据参数替换参数变为?
		String newSQL = SQLUtils.parameQuestion(insertSql, sqlInsertParameter);
		System.out.println("newSQL:" + newSQL + ",sqlParams:" + sqlParams.toString());
		// 5. 调用jdbc底层代码执行语句
		return JDBCUtils.insert(newSQL, false, sqlParams);
	}

	private List<Object> sqlParams(String[] sqlInsertParameter, ConcurrentHashMap<Object, Object> paramsMap) {
		List<Object> sqlParams = new ArrayList<>();
		for (String paramName : sqlInsertParameter) {
			Object paramValue = paramsMap.get(paramName);
			sqlParams.add(paramValue);
		}
		return sqlParams;
	}

	private ConcurrentHashMap<Object, Object> paramsMap(Object proxy, Method method, Object[] args) {
		ConcurrentHashMap<Object, Object> paramsMap = new ConcurrentHashMap<>();
		// 获取方法上的参数
		Parameter[] parameters = method.getParameters();
		for (int i = 0; i < parameters.length; i++) {
			Parameter parameter = parameters[i];
			ExtParam extParam = parameter.getDeclaredAnnotation(ExtParam.class);
			if (extParam != null) {
				// 参数名称
				String paramName = extParam.value();
				Object paramValue = args[i];
				// System.out.println(paramName + "," + paramValue);
				paramsMap.put(paramName, paramValue);
			}
		}
		return paramsMap;
	}

	public Object extInsertSQL() {
		return object;
	}
}

package com.itmayiedu.orm.mybatis.aop;

import com.itmayiedu.entity.User;
import com.itmayiedu.mapper.UserMapper;
import com.itmayiedu.sql.SqlSession;

public class Test0003 {

	public static void main(String[] args) {
		// 使用动态代理技术虚拟调用方法
		UserMapper userMapper = SqlSession.getMapper(UserMapper.class);
		User selectUser = userMapper.selectUser("张三", 644064);
		System.out.println(
				"结果:" + selectUser.getUserName() + "," + selectUser.getUserAge() + ",id:" + selectUser.getId());
		// // 先走拦截invoke
		// int insertUserResult = userMapper.insertUser("张三", 644064);
		// System.out.println("insertUserResult:" + insertUserResult);
	}

}

在这里插入图片描述

package com.itmayiedu.sql;

import java.lang.reflect.Proxy;

import com.itmayiedu.orm.mybatis.aop.MyInvocationHandlerMbatis;

public class SqlSession {

	// 加载Mapper接口
	public static <T> T getMapper(Class classz) {
		return (T) Proxy.newProxyInstance(classz.getClassLoader(), new Class[] { classz },
				new MyInvocationHandlerMbatis(classz));
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值