mybatis 源码解析,mybatis 数据源
00-1010前言jdbc思考传统JDBC源代码分析和数据源总结的弊端
00-1010上述MyBatis部署运行并根据官网运行一个demo:一步部署运行MyBatis3源代码保姆级。
00-1010张贴JDBC操作的另一种测试方法。流程是:
加载JDBC驱动程序;获取数据库连接;创建JDBC报表对象;设置SQL语句的传入参数;执行SQL语句并获得查询结果;转换查询结果并返回处理结果;释放相关资源(关闭连接、关闭语句、关闭结果集);@ Test public void JDBC Test(){ String driver= com . MySQL . CJ . JDBC . driver ;string URL= JDBC : my SQL ://localhost :3306/news?character encoding=utf 8 server time zone=Asia/Shanghai use SSL=false allowpublickeyretrieval=true ;字符串user= rootString pwd= root123456Connection connection=null结果集rs=nullPreparedStatement stmt=null尝试{ class . forname(driver);//Get数据库连接connection=driver manager . Get connection(URL,user,pwd);字符串SQL= select * from t _ level where name=?;//创建一个语句对象(每条语句都是一个数据库执行请求)stmt=connection . prepare Statement(SQL);//设置传入参数stmt.setString(1,张三);//执行SQL语句RS=stmt . Execute query(SQL);resultset metaData metaData=RS . get metaData();//处理查询结果——这里什么都不做。int column count=metadata . get column count();system . out . println(column count);} catch(Exception e){ e . printstacktrace();}最后{try{ //关闭结果集if(rs!=null){ RS . close();rs=null}//如果(stmt!=null){ stmt . close();stmt=null}如果(连接!=null){ connection . close();connection=null} } catch(SQLException e){ e . printstacktrace();} } }
目录
JDBC底层不使用连接池,需要频繁创建和关闭连接来操作数据库,消耗大量资源;最初的JDBC代码是用Java编写的。一旦SQL需要修改,Java需要整体编译,不利于系统维护。如果PreparedStatement是预编译的,则变量设置为数字,如1、2、3等。而且这样的序列号不利于维护;result返回的结果集也需要硬编码。00-1010对比上面的JDBC测试案例和mybatis测试案例,你能发现什么共同点?
点?
@Test public void test() throws IOException { InputStream input = Resources.getResourceAsStream("SqlSessionConfig.xml"); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(input); SqlSession sqlSession = sessionFactory.openSession(); LevelDao dao = sqlSession.getMapper(LevelDao.class); List<Level> all = dao.findAll(); }首先他们都要有数据源,这是毋庸置疑的。其次还要有执行sql语句,再有就是执行操作。
源码分析
接下来进入到源码分析阶段。由于我们是根据官网 Building SqlSessionFactory from XML的方式来测试demo的,接下来我们的解析就按照XML文件配置形式来讲解。
获取数据源
数据源4大元素包括:驱动、 url、 用户名、 密码。在看代码之前,先看一下我们的配置文件结构。
mybatis是什么时候获取到数据源的呢?要从测试方法生成SqlSessionFactory说起。
通过断点进入到SqlSessionFactoryBuilder
的build
方法中,方法体就两行关键代码,首先new了一个XML 配置生成器
,接着调用了其parse()生成一个Configuration
对象。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }parse方法执行了下面这条语句:
parseConfiguration(parser.evalNode("/configuration"));
parser.evalNode
会生成一个mybatis封装的XNode
对象,copy后发现就是我们配置文件中<configuration>
标签中的内容。
进入到parseConfiguration
方法中,可以看出好多方法的字符串参数都和我们<configuration>
标签中的一些标签名称相同。没错,每一步都是去扫描到对应参数的标签内容从而进行一些配置处理。
private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }我们此处不研究其他处内容,直接看
environmentsElement
方法的内容。root.evalNode("environments")
返回的XNode对象的value就是我们的environments
标签内容。
进入到environmentsElement
方法中,会循环遍历下一级的environment
,此处便是解析xml配置多数据源的地方。
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } //xml配置多数据源 for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); //<dataSource></dataSource> DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); //获得到数据库源 DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } } } }
dataSourceElement
方法会拿到dataSource
标签的内容生成一个DataSourceFactory
,并根据我们的配置给其属性赋值。 通过getDataSource()
方法便可以拿到我们的数据源。
最后调用configuration.setEnvironment
给到全局配置中的。
执行流程图如下:
总结
到此这篇关于MyBatis3源码解析之如何获取数据源的文章就介绍到这了,更多相关MyBatis3获取数据源内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。