摘要:三大巨頭結(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 MapmappedStatements = 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); } publicT selectOne(String statement, Object parameter) { List
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; } publicList 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
摘要:核心流程三大階段縷清思路也就是核心流程之后,我們就開(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...
摘要:邊界清晰,有利于理解開(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...
摘要:通過(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:/...
摘要:基本綱要組成動(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)...
摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫(xiě),讓大家對(duì)的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類(lèi),用于解析配置文件加載相關(guān)環(huán)境。配置模塊這里的對(duì)框架的配置使用了簡(jiǎn)單的,主要原因還是簡(jiǎn)單易懂然后節(jié)省時(shí)間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫(xiě)mybatis,讓大家對(duì)mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...
閱讀 664·2021-08-17 10:15
閱讀 1779·2021-07-30 14:57
閱讀 1998·2019-08-30 15:55
閱讀 2846·2019-08-30 15:55
閱讀 2731·2019-08-30 15:44
閱讀 695·2019-08-30 14:13
閱讀 2411·2019-08-30 13:55
閱讀 2612·2019-08-26 13:56