摘要:三大巨頭結果集再通過反射機制映射到對象上面,便做好了數據的映射關于映射具體內容可查閱資料及源碼到這我們已經完成了一個簡易的框架了通過手寫一個簡單的框架,我們就可以看得懂源碼了,學習框架設計的思路并且增強我們的內功
簡化版Mybatis實現思路
1.創建SqlSessionFactory實例.
2.實例化過程中,加載配置文件創建configuration對象.
3.通過factory創建SqlSession對象,把configuaration傳入SqlSession.
4.通過SqlSession獲取mapper接口動態代理
5.通過代理對調sqlsession中查詢方法;
6.sqlsession將查詢方法轉發給executor;
7.executor基于JDBC訪問數據庫獲取數據;
8.executor通過反射將數據轉換成POJO并返回給sqlsession;
9.數據返回給調用者
上節講到快速入門mybatis的demo三大階段
// 1.讀取mybatis配置文件創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.獲取對應mapper TUserMapper mapper = sqlSession.getMapper(TUserMapper.class); //-------------第三階段------------- // 4.執行查詢語句并返回結果 TUser user = mapper.selectByPrimaryKey(1); System.out.println(user.toString());第一階段:
第一階段先把配置文件加載到內存,包括數據庫信息和mapper.xml。
針對mapper.xml我們定義一個MappedStatement類來存入相應信息.
public class MappedStatement { //此處忽略getset方法 private String namespace;//xml里面的namespace即mapper接口路徑 private String sourceId;//mapper接口路徑+xml里面的每一個id private String sql;//sql語句 private String resultType;//返回類型 }
再定義一個全局配置信息即Configuration存放所有配置信息:
public class Configuration { //記錄mapper xml文件存放的位置 public static final String MAPPER_CONFIG_LOCATION = "config"; //記錄數據庫連接信息文件存放位置 public static final String DB_CONFIG_FILE = "db.properties"; private String dbUrl; private String dbUserName; private String dbPassword; private String dbDriver; //mapper xml解析完以后select節點的信息存放在mappedStatements,key為MappedStatement里面 //的sourceId protected final MapmappedStatements = new HashMap (); //為mapper接口生成動態代理的方法 public T getMapper(Class type, SqlSession sqlSession) { return MapperProxyFactory.getMapperProxy(sqlSession, type); } }
SqlSessionFactory實例化,并加載configuaration對象信息,這樣就把所有的配置信息加載到內存里
public class SqlSessionFactory { //配置對象全局唯一 加載數據庫信息和mapper文件信息 private Configuration conf = new Configuration(); public SqlSessionFactory() { //加載數據庫信息 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) { // 創建saxReader對象 SAXReader reader = new SAXReader(); // 通過read方法讀取一個文件 轉換成Document對象 Document document=null; try { document = reader.read(file); } catch (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } //獲取根節點元素對象 Element node = document.getRootElement(); //獲取命名空間 String namespace = node.attribute("namespace").getData().toString(); //獲取select子節點列表 List第二階段selects = node.elements("select"); for (Element element : selects) {//遍歷select節點,將信息記錄到MappedStatement對象,并登記到configuration對象中 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對象中 } } 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動態代理.
Sqlsession
mybatis暴露給外部的接口,實現增刪改查的能力
1.對外提供數據訪問的api
2.對內將請求轉發給executor
3.executor基于JDBC訪問數據庫
public class DefaultSqlSession implements SqlSession { //配置對象全局唯一 加載數據庫信息和mapper文件信息 private Configuration conf; //真正提供數據庫訪問能力的對象 private Executor executor; public DefaultSqlSession(Configuration conf) { super(); this.conf = conf; executor = new SimpleExecutor(conf); } publicT selectOne(String statement, Object parameter) { List
Executor是Mybatis核心接口定義了數據庫操作的基本方法,Sqlsession都是基于它來實現的
public interface Executor {List query(MappedStatement ms, Object parameter) throws SQLException; T selectOne(String statement,Object parameter);
}
Executor實現類:
public class SimpleExecutor implements Executor { private Configuration conf; public SimpleExecutor(Configuration conf) { this.conf = conf; } publicList query(MappedStatement ms, Object parameter) throws SQLException { //獲取mappedStatement對象,里面包含sql語句和目標對象等信息; MappedStatement mappedStatement = conf.getMappedStatement(ms.getSourceId()); //1.獲取Connection對象 Connection conn = getConnect(); //2.實例化StatementHandler對象,準備實例化Statement StatementHandler statementHandler = new DefaultStatementHandler(mappedStatement); //3.通過statementHandler和Connection獲取PreparedStatement PreparedStatement prepare = statementHandler.prepare(conn); //4.實例化ParameterHandler對象,對Statement中sql語句的占位符進行處理 ParameterHandler parameterHandler = new DefaultParameterHandler(parameter); parameterHandler.setParameters(prepare); //5.執行查詢語句,獲取結果集resultSet ResultSet resultSet = statementHandler.query(prepare); //6.實例化ResultSetHandler對象,對resultSet中的結果集進行處理,轉化成目標對象 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接口在我們工程里面沒有實現類,是通過動態代理來執行方法的.
/** * mapper接口生成動態代理的工程類 * */ 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實現類:
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本身的方法不增強 return method.invoke(this, args); } Class> returnType = method.getReturnType();// 獲取方法的返回參數class對象 Object ret = null; if (isCollection(returnType)) {// 根據不同的返回參數類型調用不同的sqlsession不同的方法 ret = sqlSession.selectList(mapperInterface.getName()+"."+ method.getName(), args); } else { ret = sqlSession.selectOne(mapperInterface.getName()+"."+ method.getName(), args); } return ret; } }
第三階段執行查詢并返回結果.剛剛講過我們執行數據庫操作實際上是executor基于jdbc執行的。
jdbc三大巨頭,Connection,PreparedStatement,ResultSet,
結果集Result再通過反射機制映射到對象上面,便做好了數據的映射(關于映射具體內容可查閱資料及源碼),到這我們已經完成了一個簡易的Mybatis框架了.
通過手寫一個簡單的Mybatis框架,我們就可以看得懂源碼了,學習框架設計的思路并且增強我們Java的內功.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74470.html
摘要:核心流程三大階段縷清思路也就是核心流程之后,我們就開始寫代碼了,詳見下節 Mybatis快速入門 步驟: 1.加入mybatis的依賴 2.添加Mybatis的配置文件 3.場景介紹 4.編寫實體類丶mapper接口及mapper.xml文件 5.編寫測試代碼 demo: public class TUser { private Integer id; priva...
摘要:通過整合及可以實現數據庫查詢后將數據持久化。但是可能出現幻像讀這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。 所需技術:spring、mybatis、druid、flyway、logback、nodejs、html、css3 ;目標:創建一個業務框架,后端采用spring+mybatis,中間層采用node,前端html5,css3等; showImg(https:/...
摘要:基本綱要組成動態配置配置核心源碼分析源碼解析源碼解析源碼解析源碼解析手寫框架是什么本質是一種半自動的框架,前身是其源于和的組合,除了和映射關系之外,還需要編寫語句映射三要素映射規則快速入門加入的依賴添加的配置文件場景介紹編寫實體類接口以及文 showImg(https://segmentfault.com/img/bVblrnC); Mybatis基本綱要 Mybatis組成 · 動態...
摘要:前言嗨,小伙伴們,這篇博文將帶大家手寫,讓大家對的核心原理以及工作流程有更加深刻的理解。模塊顧名思義,就是框架配置類,用于解析配置文件加載相關環境。配置模塊這里的對框架的配置使用了簡單的,主要原因還是簡單易懂然后節省時間。 前言 (????)??嗨,小伙伴們,這篇博文將帶大家手寫mybatis,讓大家對mybaits的核心原理以及工作流程有更加深刻的理解。在上篇Spring-Mybat...
閱讀 632·2021-08-17 10:15
閱讀 1715·2021-07-30 14:57
閱讀 1971·2019-08-30 15:55
閱讀 2813·2019-08-30 15:55
閱讀 2704·2019-08-30 15:44
閱讀 662·2019-08-30 14:13
閱讀 2380·2019-08-30 13:55
閱讀 2588·2019-08-26 13:56