# 手写实现Mybatis —>单表查询
1. Mybatis核心概念
名称 | 意义 |
---|---|
Configuration | 管理mysql-config.xml 全局配置关系类 |
SqlSessionFactorySession | 管理工厂接口SessionSqlSession |
Session | SqlSession 是一个面向用户(程序员)的接口。SqlSession 中提 |
Executor | 作用:SqlSession 内部通过执行器操作数据库 |
MappedStatement | 底层封装对象,作用:对操作数据库存储封装,包括 sql 语句、输入输出参数 |
StatementHandler | 具体操作数据库相关的 handler 接口 |
ResultSetHandler | 具体操作数据库返回结果的 handler 接口 |
2. Mybatis处理流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mRgaYSdG-1591682568264)(https://img2020.cnblogs.com/blog/1999821/202004/1999821-20200430204019808-2075197123.png)]
-
各层包搭建树状图
-
│ │ │ └─com │ │ │ └─mybatis │ │ │ ├─binding | | | └─ MapperMethod.class | | | ├─ MapperProxy.class | | | └─ MapperRegister.class │ │ │ ├─executor | | | └─ MapperMethod.class | | | ├─ MapperProxy.class | | | └─ MapperRegister.class │ │ │ ├─resultset | | | └─ DefaultResultHandler.class | | | └─ ResultSetHandler.class │ │ │ ├─session | | | └─ Configuration.class | | | ├─ DefaultSQLSession.class | | | ├─ SQLSession.class | | | ├─ SQLSessionFactory.class | | | └─ sqlSessionFactoryBuilder.class │ │ │ └─statement │ │ │ └─ StatementHandler.class | | | │ │ └─resources │ │ └─mybatis │ └─test │ └─java │ └─com │ └─qitian │ ├─mapper │ └─pojo
3. Mybatis 实现的主要类
-
Configuration
-
SqlSessionFactory
-
Executor
1. Configuration
configuration类的作用主要是读取mybatis-congig.xml的配置文件,以及mapper注册(将配置文件的XXXMapper.xml存储到一个Map集合中)。
Mappper注册
MapperRegister.class
@Data
public class MapperRegister {
private Map<String, MapperMethod> knownMappers = new HashMap<String, MapperMethod>();
}
Configuration.class
/**
* 读取xml文件
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Configuration {
/**
* 定义io 读取xml文件
*/
private InputStream inputStream;
private MapperRegister mapperRegister = new MapperRegister();
public void loadCOnfigurations() throws Exception {
try {
Document document = new SAXReader().read(inputStream);
Element root = document.getRootElement();
//读取mappers下配置的mapper
List<Element> mappers = root.element("mappers").elements("mapper");
for (Element mapper : mappers) {
//获取mapper里的属性resource
/**
<!--mapper映射-->
<mappers>
<mapper resource="XXXMapper.xml"/>
</mappers>
*/
if (mapper.attribute("resource") != null) {
mapperRegister.setKnownMappers((Map<String, MapperMethod>) loadXMLConfiguration(mapper.attributeValue("resource")));
}
if (mapper.attribute("class") != null) {
}
}
} catch (DocumentException e) {
System.out.println("读取配置文件出错");
e.printStackTrace();
} finally {
inputStream.close();
}
}
/**
* 读取XXXMapper.xml的信息
*
* @param reource
* @return
*/
private Object loadXMLConfiguration(String reource) throws Exception {
Map<String, MapperMethod> map = new HashMap<String, MapperMethod>();
InputStream is = null;
try {
//获取XXXMapper.xml文件
is = this.getClass().getClassLoader().getResourceAsStream(reource);
Document document = new SAXReader().read(is);
Element root = document.getRootElement();
if (root.getName().equalsIgnoreCase("mapper")) {
//读取mapper中的命名空间
String namespace = root.attribute("namespace").getText();
//读取查询方法的关键字select
for (Element select : (List<Element>) root.elements("select")) {
MapperMethod mapperMethod = new MapperMethod();
mapperMethod.setSql(select.getText().trim());
//获取返回值的类型
mapperMethod.setType(Class.forName(select.attribute("resultType").getText()));
map.put(namespace + "." + select.attribute("id").getText(), mapperMethod);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
is.close();
}
return map;
}
}
2. SqlSessionFactory
SqlSessionFactory利用SqlSessionFactoryBuilder.builer(configuration)方法创建对象,将configuration作为参数传入,以便获取mybatis-config.xml的信息,该类的主要作用是用于构建SqlSession对象,SqlSession对象可以通过方法openSession获得。(sqlSessionFactory.openSession(configuration)😉
SqlSessionFactory.class
public class SqlSessionFactory {
public SqlSession openSession(Configuration configuration){
return new DefaultSqlSession(configuration,new SimpleExecutor(configuration));
}
}
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Configuration configuration) throws Exception {
configuration.loadCOnfigurations();
return new SqlSessionFactory();
}
}
DefaultSqlSession为SqlSession的实现类,主要实现Mapper的动态代理,代理底层主要通过Cglib实现,以及查询方法的实现。
DefaultSqlSession.class
@AllArgsConstructor
@Data
public class DefaultSqlSession implements SqlSession {
private Configuration configurauion;
private Executor exceutor;
public <T> T selectOne(MapperMethod mapperMethod, Object statement) throws Exception {
System.out.println("=======DefaultSqlSession==========");
return (T) exceutor.query(mapperMethod,statement);
}
public <T> T getMapper(Class<T> type) {
return (T) Proxy.newProxyInstance(type.getClassLoader(),
new Class[]{type}, new MapperProxy<T>(this, type));
}
}
sqlSession.class
public interface SqlSession {
public <T> T selectOne(MapperMethod mapperMethod, Object statement) throws Exception;
<T> T getMapper(Class<T> type);
}
3. Executor
Executor的作用主要是用于执行Sql语句,SimpleExecutor实现Executor的query方法。
Executor.class
public interface Executor {
<T> T query(MapperMethod mapperMethod, Object statement) throws Exception;
}
SimpleExecutor.class
@Data
@AllArgsConstructor
public class SimpleExecutor<T> implements Executor {
private Configuration configuration;
public <T> T query(MapperMethod mapperMethod, Object statement) throws Exception {
StatementHandler statementHandler = new StatementHandler(configuration);
System.out.println("============SimpleExecutor===========");
return statementHandler.query(mapperMethod,statement);
}
}
DefaultSqlSession类通过sqlSession.getMapper(XXXX.class)获取接口的代理对象
MapperProxy.class 动态代理获取XXXMapper.class
@Data
@AllArgsConstructor
public class MapperProxy<T> implements InvocationHandler {
private final DefaultSqlSession sqlSession;
private final Class<T> mapperInterface;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MapperMethod mapperMethod = sqlSession.getConfigurauion().getMapperRegister()
.getKnownMappers().get(method.getDeclaringClass().getName() + "." + method.getName()); //获取接口的路径+方法名
if (mapperMethod != null) {
//返回存放SQL和类型的mapperMethod和传入参数
return sqlSession.selectOne(mapperMethod, String.valueOf(args[0]));
}
return method.invoke(proxy, args);
}
}
由getmapper(XXX.class)动态代理对象调用方法执行MapperProxy的invoke方法直接调用DefaultSqlSession的selectOne(MapperMethod mapperMethod, Object statement)查询,MapperMethod为存放SQL语句和对象类型的类,statement为动态代理对象调用方法时传入的参数
MapperMethod.class
/**
存放SQL语句和对象的类型
*/
@Data
public class MapperMethod<T>{
private String sql;
private Class<T> type;
public MapperMethod() {
}
public MapperMethod(String sql, Class<T> type) {
this.sql = sql;
this.type = type;
}
}
进入DefaultSQLSession的selectOne方法后,由selectOne方法调用Executor的实现类SimpleExecutor的query方法
SimpleExecutor.class
@Data
@AllArgsConstructor
public class SimpleExecutor<T> implements Executor {
private Configuration configuration;
public <T> T query(MapperMethod mapperMethod, Object statement) throws Exception {
StatementHandler statementHandler = new StatementHandler(configuration);
System.out.println("============SimpleExecutor===========");
return statementHandler.query(mapperMethod,statement);
}
}
之后执行statementHandler的query,执行数据库相关JDBC的方法,
StatementHandler.class
@Data
@AllArgsConstructor
public class StatementHandler {
private Configuration configuration;
private ResultSethandler resultSethandler;
public StatementHandler(Configuration configuration) {
resultSethandler = new DefaultResultSetHandler();
this.configuration = configuration;
}
//查询
public <T> T query(MapperMethod mapperMethod, Object statement) throws Exception {
//1.加载驱动程序
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得数据库连接
Connection conn = DriverManager.getConnection("url", "admin", "passsword");
String format = String.format(mapperMethod.getSql(), Integer.valueOf((String) statement));
PreparedStatement preparedStatement = conn.prepareStatement(format);
preparedStatement.execute();
ResultSet resultSet = preparedStatement.getResultSet();
return resultSethandler.handle(preparedStatement, mapperMethod);
}
}
返回对象根据ResultSethandler的实现类DefaultResultSetHandler的handle方法判断再返回
DefaultResultSetHandler.class
public class DefaultResultSetHandler implements ResultSethandler {
public <T> T handle(PreparedStatement preparedStatement, MapperMethod mapperMethod) throws Exception {
Object resultObj = new DefaultObjectFactory().create(mapperMethod.getType());
ResultSet resultSet = preparedStatement.getResultSet();
if (resultSet.next()) { //todo
int i = 0;
for (Field field : resultObj.getClass().getDeclaredFields()) {
setValue(resultObj, field, resultSet, i);
}
}
return (T) resultObj;
}
private void setValue(Object resultObj, Field field, ResultSet resultSet, int i) throws Exception {
Method method = resultObj.getClass().getMethod("set" + upperCapital(field.getName()), field.getType());
method.invoke(resultObj, getResult(field, resultSet));
}
//判断字段的类型
private Object getResult(Field field, ResultSet resultSet) throws SQLException {
Class<?> type = field.getType();
if (Integer.class == type) {
return resultSet.getInt(field.getName());
}
if (String.class == type) {
return resultSet.getString(field.getName());
}
if (Long.class == type) {
return resultSet.getString(field.getName());
}
if (Date.class == type) {
return resultSet.getString(field.getName());
}
if (Dubble.class == type) {
return resultSet.getString(field.getName());
}
if (Float.class == type) {
return resultSet.getString(field.getName());
}
if (Bigdicail.class == type) {
return resultSet.getString(field.getName());
}
return resultSet.getString(field.getName());
}
//将拼接字段
private String upperCapital(String name) {
String s = name.substring(0, 1);
String substring = name.substring(1);
return s.toUpperCase() + substring;
}
}
测试代码
public class TestMybatis {
public static void main(String[] args) throws Exception {
//读取配置文件
InputStream inputStream = TestMybatis.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
Configuration configuration = new Configuration();
//将读取到的配置文件字符流设置到configuration中
configuration.setInputStream(inputStream);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession(configuration);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Account user = userMapper.getUserById(123456L);
System.err.println(user);
}
}
效果实现图
转载:请标注:https://blog.csdn.net/qq_40482053/article/details/106640184