栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手动实现一个简单的 MyBatis

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手动实现一个简单的 MyBatis

 

(一)、创建 SqlSessionFactory 实例。

(二)、实例化过程,加载配置文件创建 Configuration 对象。

(三)、通过 factory 创建 SqlSession。

(四)、通过 SqlSession 获取 mapper 接口动态代理。

(五)、动态代理回调 SqlSession 中某查询方法。

(六)、SqlSession 将查询方法转发给 Executor。

(七)、Executor 基于 JDBC 访问数据库获取数据。

(八)、Executor 通过反射将数据转换成 POJO并返回给 SqlSession。

(九)、将数据返回给调用者。

项目整体使用 Maven 构建,mybatis-demo 是脱离 Spring 的 MyBatis 使用的例子。paul-mybatis 是我们自己实现的 mybatis 框架。



 

首先按照我们以前的使用 mybatis 代码时的流程,创建 mapper 接口,xml 文件,和 POJO以及集一些配置文件。

1、接口:TUserMapper

 

2、xml 文件:

3、实体类,属性应该与数据库想匹配:

 

4、数据库连接配置文件、db.properties:


 

关注 xml 文件,mapper 文件里的 namespace,id,resultType 和 sql 语句都要存储起来,我们定义一个 POJO 来存储这些信息。 

创建一个 Configuration 类,用来保存所有配置文件和 xml 文件里的信息:

 

有了配置类之后,我们可以通过这个配置类构建一个 SqlSessionFactory 了。

5、 SqlSessionFactory 抽象模版



 

Default 实现类主要完成了两个功能,加载配置信息到 Configuration 对象里,实现创建 SqlSession 的功能。

  package com.paul.mybatis.factory;
  import com.paul.mybatis.confiuration.Configuration;
  import com.paul.mybatis.confiuration.MappedStatement;
  import com.paul.mybatis.sqlsession.DefaultSqlSession;
  import com.paul.mybatis.sqlsession.SqlSession;
  import org.dom4j.document;
  import org.dom4j.documentException;
  import org.dom4j.Element;
  import org.dom4j.io.SAXReader;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Properties;
  
  public class DefaultSqlSessionFactory implements SqlSessionFactory{
      //希望Configuration 是单例子并且唯一的
      private final Configuration configuration = new Configuration();
      // xml 文件存放的位置
      private static final String MAPPER_CONFIG_LOCATION = "mappers";
      // 数据库信息存放的位置
      private static final String DB_CONFIG_FILE = "db.properties";
      public DefaultSqlSessionFactory() {
          loadDBInfo();
          loadMapperInfo();
      }
      private void loadDBInfo() {
          InputStream db = this.getClass().getClassLoader().getResourceAsStream(DB_CONFIG_FILE);
          Properties p = new Properties();
          try {
              p.load(db);
          } catch (IOException e) {
              e.printStackTrace();
          }
          //将配置信息写入Configuration 对象
          configuration.setJdbcDriver(p.get("jdbc.driver").toString());
          configuration.setJdbcUrl(p.get("jdbc.url").toString());
          configuration.setJdbcUsername(p.get("jdbc.username").toString());
          configuration.setJdbcPassword(p.get("jdbc.password").toString());
      }
      //解析并加载xml文件
      private void loadMapperInfo(){
          URL resources = null;
          resources = this.getClass().getClassLoader().getResource(MAPPER_CONFIG_LOCATION);
          File mappers = new File(resources.getFile());
          //读取文件夹下面的文件信息
          if(mappers.isDirectory()){
              File[] files = mappers.listFiles();
              for(File file:files){
                  loadMapperInfo(file);
              }
          }
      }
      private void loadMapperInfo(File file){
          SAXReader reader = new SAXReader();
          //通过read方法读取一个文件转换成document 对象
          document document = null;
          try {
              document = reader.read(file);
          } catch (documentException e) {
              e.printStackTrace();
          }
          //获取根结点元素对象
          Element e = document.getRootElement();
          //获取命名空间namespace
          String namespace = e.attribute("namespace").getData().toString();
          //获取select,insert,update,delete子节点列表
          List selects = e.elements("select");
          List inserts = e.elements("select");
          List updates = e.elements("select");
          List deletes = e.elements("select");
          List all = new ArrayList<>();
          all.addAll(selects);
          all.addAll(inserts);
          all.addAll(updates);
          all.addAll(deletes);
          //遍历节点,组装成 MappedStatement 然后放入到configuration 对象中
          for(Element ele:all){
              MappedStatement mappedStatement = new MappedStatement();
              String id = ele.attribute("id").getData().toString();
              String resultType = ele.attribute("resultType").getData().toString();
              String sql = ele.getData().toString();
              mappedStatement.setId(namespace+"."+id);
              mappedStatement.setResultType(resultType);
              mappedStatement.setNamespace(namespace);
              mappedStatement.setSql(sql);
              configuration.getMappedStatement().put(namespace+"."+id,mappedStatement);
          }
      }
      @Override
      public SqlSession openSession() {
          return new DefaultSqlSession(configuration);
      }
  }

在 SqlSessionFactory 里创建了 DefaultSqlSession,我们看看它的具体实现。SqlSession里面应该封装了所有数据库的具体操作和一些获取 mapper 实现类的方法。使用动态代理生成一个加强类。这里面最终还是把数据库的相关操作转给 SqlSession,使用 mapper 能使编程更加优雅。

SqlSession 接口,定义模版方法

 

Default 的 SqlSession 实现类。里面需要传入 Executor,这个 Executor 里面封装了 JDBC 操作数据库的流程。我们重点关注 getMapper 方法。

动态代理的 InvocationHandler

 

最后来看我们的测试类

 

                                                                         需要更多教程,微信扫码即可

                                                                              

                                                                                         

                                                        别忘了扫码领资料哦【高清Java学习路线图】

                                                                     和【全套学习视频及配套资料】
  
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/462989.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号