成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

解密Mybatis,手寫(xiě)Mybatis框架(二)

chuyao / 2538人閱讀

摘要:三大巨頭結(jié)果集再通過(guò)反射機(jī)制映射到對(duì)象上面,便做好了數(shù)據(jù)的映射關(guān)于映射具體內(nèi)容可查閱資料及源碼到這我們已經(jīng)完成了一個(gè)簡(jiǎn)易的框架了通過(guò)手寫(xiě)一個(gè)簡(jiǎn)單的框架,我們就可以看得懂源碼了,學(xué)習(xí)框架設(shè)計(jì)的思路并且增強(qiáng)我們的內(nèi)功

簡(jiǎn)化版Mybatis實(shí)現(xiàn)思路

1.創(chuàng)建SqlSessionFactory實(shí)例.

2.實(shí)例化過(guò)程中,加載配置文件創(chuàng)建configuration對(duì)象.

3.通過(guò)factory創(chuàng)建SqlSession對(duì)象,把configuaration傳入SqlSession.

4.通過(guò)SqlSession獲取mapper接口動(dòng)態(tài)代理

5.通過(guò)代理對(duì)調(diào)sqlsession中查詢(xún)方法;

6.sqlsession將查詢(xún)方法轉(zhuǎn)發(fā)給executor;

7.executor基于JDBC訪問(wèn)數(shù)據(jù)庫(kù)獲取數(shù)據(jù);

8.executor通過(guò)反射將數(shù)據(jù)轉(zhuǎn)換成POJO并返回給sqlsession;

9.數(shù)據(jù)返回給調(diào)用者

上節(jié)講到快速入門(mén)mybatis的demo三大階段

// 1.讀取mybatis配置文件創(chuàng)SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
//-------------第二階段-------------
// 2.獲取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.獲取對(duì)應(yīng)mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);

//-------------第三階段-------------
// 4.執(zhí)行查詢(xún)語(yǔ)句并返回結(jié)果
TUser user = mapper.selectByPrimaryKey(1);
System.out.println(user.toString());
第一階段:

第一階段先把配置文件加載到內(nèi)存,包括數(shù)據(jù)庫(kù)信息和mapper.xml。

針對(duì)mapper.xml我們定義一個(gè)MappedStatement類(lèi)來(lái)存入相應(yīng)信息.

public class MappedStatement {
    //此處忽略getset方法
    private String namespace;//xml里面的namespace即mapper接口路徑
    
    private String sourceId;//mapper接口路徑+xml里面的每一個(gè)id
    
    private String sql;//sql語(yǔ)句
    
    private String resultType;//返回類(lèi)型    

}

再定義一個(gè)全局配置信息即Configuration存放所有配置信息:

public class Configuration {
    //記錄mapper xml文件存放的位置
    public static final String MAPPER_CONFIG_LOCATION = "config";
    //記錄數(shù)據(jù)庫(kù)連接信息文件存放位置
    public static final String DB_CONFIG_FILE = "db.properties";
    
    private String dbUrl;

    private String dbUserName;

    private String dbPassword;

    private String dbDriver;

    //mapper xml解析完以后select節(jié)點(diǎn)的信息存放在mappedStatements,key為MappedStatement里面 
     //的sourceId
    protected final Map mappedStatements = new HashMap();
    
    //為mapper接口生成動(dòng)態(tài)代理的方法
public  T getMapper(Class type, SqlSession sqlSession) {
    return MapperProxyFactory.getMapperProxy(sqlSession, type);
}
}

SqlSessionFactory實(shí)例化,并加載configuaration對(duì)象信息,這樣就把所有的配置信息加載到內(nèi)存里

public class SqlSessionFactory {
    //配置對(duì)象全局唯一 加載數(shù)據(jù)庫(kù)信息和mapper文件信息
    private Configuration conf = new Configuration();

    public SqlSessionFactory() {
        //加載數(shù)據(jù)庫(kù)信息
         loadDbInfo();
         //加載mapper文件信息
         loadMappersInfo();
    }
    
    private void loadMappersInfo() {
        URL resources =null;
        resources = SqlSessionFactory.class.getClassLoader().getResource(conf.MAPPER_CONFIG_LOCATION);
        File mappers = new File(resources.getFile());
        if(mappers.isDirectory()){
            File[] listFiles = mappers.listFiles();
            for (File file : listFiles) {
                loadMapperInfo(file);
            }
        }
    }

    private void loadMapperInfo(File file) {
        // 創(chuàng)建saxReader對(duì)象  
        SAXReader reader = new SAXReader();  
        // 通過(guò)read方法讀取一個(gè)文件 轉(zhuǎn)換成Document對(duì)象  
        Document document=null;
        try {
            document = reader.read(file);
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
        //獲取根節(jié)點(diǎn)元素對(duì)象  
        Element node = document.getRootElement();
        //獲取命名空間
        String namespace = node.attribute("namespace").getData().toString();
        //獲取select子節(jié)點(diǎn)列表
        List selects = node.elements("select");
        for (Element element : selects) {//遍歷select節(jié)點(diǎn),將信息記錄到MappedStatement對(duì)象,并登記到configuration對(duì)象中
            MappedStatement mappedStatement = new MappedStatement();
            String id = element.attribute("id").getData().toString();
            String resultType = element.attribute("resultType").getData().toString();
            String sql = element.getData().toString();
            String sourceId = namespace+"."+id;
            mappedStatement.setSourceId(sourceId);
            mappedStatement.setResultType(resultType);
            mappedStatement.setSql(sql);
            mappedStatement.setNamespace(namespace);
            conf.getMappedStatements().put(sourceId, mappedStatement);//登記到configuration對(duì)象中
        }
    }

    private void loadDbInfo() {
        InputStream dbIn = SqlSessionFactory.class.getClassLoader().getResourceAsStream(conf.DB_CONFIG_FILE);
         Properties p = new Properties();
         try {
            p.load(dbIn);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         conf.setDbDriver(p.get("jdbc.driver").toString());
         conf.setDbPassword(p.get("jdbc.password").toString());
         conf.setDbUrl(p.get("jdbc.url").toString());
         conf.setDbUserName(p.get("jdbc.username").toString());
    }
    public SqlSession openSession(){
        SqlSession sqlSession  = new DefaultSqlSession(conf);
        return sqlSession;
    }
}

第二階段

第二階段為獲取Sqlsession并且從sqlsession獲取mapper動(dòng)態(tài)代理.

Sqlsession

mybatis暴露給外部的接口,實(shí)現(xiàn)增刪改查的能力

1.對(duì)外提供數(shù)據(jù)訪問(wèn)的api

2.對(duì)內(nèi)將請(qǐng)求轉(zhuǎn)發(fā)給executor

3.executor基于JDBC訪問(wèn)數(shù)據(jù)庫(kù)

public class DefaultSqlSession implements SqlSession {
       
       //配置對(duì)象全局唯一 加載數(shù)據(jù)庫(kù)信息和mapper文件信息
       private Configuration conf;
       
       //真正提供數(shù)據(jù)庫(kù)訪問(wèn)能力的對(duì)象
       private Executor executor;
       
   
       public DefaultSqlSession(Configuration conf) {
           super();
           this.conf = conf;
           executor = new SimpleExecutor(conf);
       }
   
       public  T selectOne(String statement, Object parameter) {
           List selectList = this.selectList(statement, parameter);
           if(selectList==null||selectList.size()==0){
               return null;
           }
           if(selectList.size()==1){
               return (T) selectList.get(0);
           }else {
               throw new RuntimeException("Too Many Result!");
           }
   
       }
   
       public  List selectList(String statement, Object parameter) {
           MappedStatement mappedStatement = conf.getMappedStatement(statement);
           try {
               return executor.query(mappedStatement, parameter);
           } catch (SQLException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
           return null;
       }
   
         @Override
         //獲取當(dāng)前mapper接口的動(dòng)態(tài)代理
         public  T getMapper(Class type) {
           return conf.getMapper(type, this);
         }
   
   }

Executor是Mybatis核心接口定義了數(shù)據(jù)庫(kù)操作的基本方法,Sqlsession都是基于它來(lái)實(shí)現(xiàn)的

 public interface Executor {


  List query(MappedStatement ms, Object parameter) throws SQLException;


  T selectOne(String statement,Object parameter);

}

Executor實(shí)現(xiàn)類(lèi):

public class SimpleExecutor implements Executor {

        
        private Configuration conf;
    
    
        public SimpleExecutor(Configuration conf) {
            this.conf = conf;
        }

        public  List query(MappedStatement ms, Object parameter)
                throws SQLException {
            //獲取mappedStatement對(duì)象,里面包含sql語(yǔ)句和目標(biāo)對(duì)象等信息;
            MappedStatement mappedStatement = conf.getMappedStatement(ms.getSourceId());
            //1.獲取Connection對(duì)象
            Connection conn = getConnect();
            //2.實(shí)例化StatementHandler對(duì)象,準(zhǔn)備實(shí)例化Statement
            StatementHandler statementHandler = new DefaultStatementHandler(mappedStatement);
            //3.通過(guò)statementHandler和Connection獲取PreparedStatement
            PreparedStatement prepare = statementHandler.prepare(conn);
            //4.實(shí)例化ParameterHandler對(duì)象,對(duì)Statement中sql語(yǔ)句的占位符進(jìn)行處理
            ParameterHandler parameterHandler = new DefaultParameterHandler(parameter);
            parameterHandler.setParameters(prepare);
            //5.執(zhí)行查詢(xún)語(yǔ)句,獲取結(jié)果集resultSet
            ResultSet resultSet = statementHandler.query(prepare);
            //6.實(shí)例化ResultSetHandler對(duì)象,對(duì)resultSet中的結(jié)果集進(jìn)行處理,轉(zhuǎn)化成目標(biāo)對(duì)象
            ResultSetHandler resultSetHandler = new DefaultResultSetHandler(mappedStatement);
            return resultSetHandler.handleResultSets(resultSet);
        }
    
        @Override
        public  T selectOne(String statement, Object parameter) {
            MappedStatement mappedStatement =conf.getMappedStatements().get(statement);
            return null;
        }
    
    
        private Connection getConnect() {
            Connection conn =null;
            try {
                Class.forName(conf.getDbDriver());
                conn = DriverManager.getConnection(conf.getDbUrl(), conf.getDbUserName(), conf.getDbPassword());    
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return conn;
        }
    
        public Configuration getConf() {
            return conf;
        }
    
        public void setConf(Configuration conf) {
            this.conf = conf;
        }
        
    }

mapper接口在我們工程里面沒(méi)有實(shí)現(xiàn)類(lèi),是通過(guò)動(dòng)態(tài)代理來(lái)執(zhí)行方法的.

/**
 * mapper接口生成動(dòng)態(tài)代理的工程類(lèi)
 * 
 */
public class MapperProxyFactory {

  
  public static  T getMapperProxy(SqlSession sqlSession,Class mapperInterface){
      MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface);
      return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

InvocationHandler實(shí)現(xiàn)類(lèi):

public class MapperProxy implements InvocationHandler {

    private SqlSession sqlSession;
    
    private final Class mapperInterface;
    

    public MapperProxy(SqlSession sqlSession, Class mapperInterface) {
        super();
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }

    private  boolean isCollection(Class type) {
        return Collection.class.isAssignableFrom(type);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {// 如果是Object本身的方法不增強(qiáng)
            return method.invoke(this, args);
        }

        Class returnType = method.getReturnType();// 獲取方法的返回參數(shù)class對(duì)象
        Object ret = null;
        if (isCollection(returnType)) {// 根據(jù)不同的返回參數(shù)類(lèi)型調(diào)用不同的sqlsession不同的方法
            ret = sqlSession.selectList(mapperInterface.getName()+"."+ method.getName(), args);
        } else {
            ret = sqlSession.selectOne(mapperInterface.getName()+"."+ method.getName(), args);
        }

        return ret;
    }

}



第三階段

第三階段執(zhí)行查詢(xún)并返回結(jié)果.剛剛講過(guò)我們執(zhí)行數(shù)據(jù)庫(kù)操作實(shí)際上是executor基于jdbc執(zhí)行的。

jdbc三大巨頭,Connection,PreparedStatement,ResultSet,

結(jié)果集Result再通過(guò)反射機(jī)制映射到對(duì)象上面,便做好了數(shù)據(jù)的映射(關(guān)于映射具體內(nèi)容可查閱資料及源碼),到這我們已經(jīng)完成了一個(gè)簡(jiǎn)易的Mybatis框架了.

通過(guò)手寫(xiě)一個(gè)簡(jiǎn)單的Mybatis框架,我們就可以看得懂源碼了,學(xué)習(xí)框架設(shè)計(jì)的思路并且增強(qiáng)我們Java的內(nèi)功.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74470.html

相關(guān)文章

  • 解密Mybatis,手寫(xiě)Mybatis框架(一)

    摘要:核心流程三大階段縷清思路也就是核心流程之后,我們就開(kāi)始寫(xiě)代碼了,詳見(jiàn)下節(jié) Mybatis快速入門(mén) 步驟: 1.加入mybatis的依賴(lài) 2.添加Mybatis的配置文件 3.場(chǎng)景介紹 4.編寫(xiě)實(shí)體類(lèi)丶mapper接口及mapper.xml文件 5.編寫(xiě)測(cè)試代碼 demo: public class TUser { private Integer id; priva...

    SunZhaopeng 評(píng)論0 收藏0
  • Web開(kāi)發(fā)框架推導(dǎo)

    摘要:邊界清晰,有利于理解開(kāi)發(fā)測(cè)試和部署。前后端分離考慮到目前開(kāi)發(fā)流行前后端分離,為了適應(yīng)潮流,引入前后端分離的約束。該請(qǐng)求被接受處理,但是該處理是不完整的。 本文欲回答這樣一個(gè)問(wèn)題:在 「特定環(huán)境 」下,如何規(guī)劃Web開(kāi)發(fā)框架,使其能滿(mǎn)足 「期望 」? 假設(shè)我們的「特定環(huán)境 」如下: 技術(shù)層面 使用Java語(yǔ)言進(jìn)行開(kāi)發(fā) 通過(guò)Maven構(gòu)建 基于SpringBoot 使用Intelli...

    vpants 評(píng)論0 收藏0
  • 分布式軟件架構(gòu)整合(一)

    摘要:通過(guò)整合及可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)查詢(xún)后將數(shù)據(jù)持久化。但是可能出現(xiàn)幻像讀這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。 所需技術(shù):spring、mybatis、druid、flyway、logback、nodejs、html、css3 ;目標(biāo):創(chuàng)建一個(gè)業(yè)務(wù)框架,后端采用spring+mybatis,中間層采用node,前端html5,css3等; showImg(https:/...

    mochixuan 評(píng)論0 收藏0
  • 開(kāi)源框架解析,手寫(xiě)MyBatis細(xì)節(jié)思路

    摘要:基本綱要組成動(dòng)態(tài)配置配置核心源碼分析源碼解析源碼解析源碼解析源碼解析手寫(xiě)框架是什么本質(zhì)是一種半自動(dòng)的框架,前身是其源于和的組合,除了和映射關(guān)系之外,還需要編寫(xiě)語(yǔ)句映射三要素映射規(guī)則快速入門(mén)加入的依賴(lài)添加的配置文件場(chǎng)景介紹編寫(xiě)實(shí)體類(lèi)接口以及文 showImg(https://segmentfault.com/img/bVblrnC); Mybatis基本綱要 Mybatis組成 · 動(dòng)態(tài)...

    paulli3 評(píng)論0 收藏0
  • 教你手寫(xiě)Mybatis框架

    摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫(xiě),讓大家對(duì)的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類(lèi),用于解析配置文件加載相關(guān)環(huán)境。配置模塊這里的對(duì)框架的配置使用了簡(jiǎn)單的,主要原因還是簡(jiǎn)單易懂然后節(jié)省時(shí)間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫(xiě)mybatis,讓大家對(duì)mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...

    antyiwei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<