jdbc
再贴一个JDBC运行的测试方法,流程为:
-
加载JDBC驱动;
-
获取数据库连接;
-
创建JDBC Statements对象;
-
设置SQL语句的传入参数;
-
执行SQL语句并获得查询结果;
-
对查询结果进行转换处理并将处理结果返回;
-
释放相关资源(关闭Connection,关闭Statement,关闭ResultSet);
@Test public void jdbcTest(){ String driver = "com.mysql.cj.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/news?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true"; String user = "root"; String pwd = "root123456"; Connection connection=null; ResultSet rs=null; PreparedStatement stmt=null; try { Class.forName(driver); //获取数据库连接 connection = DriverManager.getConnection(url,user,pwd); String sql = "select * from t_level where name=?"; //创建Statement对象(每一个Statement为一次数据库执行请求) stmt=connection.prepareStatement(sql); //设置传入参数 stmt.setString(1,"zhangsan"); //执行SQL语句 rs = stmt.executeQuery(sql); ResultSetMetaData metaData =rs.getMetaData(); //处理查询结果-----此处未做操作 int columnCount= metaData.getColumnCount(); System.out.println(columnCount); } catch (Exception e) { e.printStackTrace(); }finally { try{ //关闭结果集 if(rs!=null){ rs.close(); rs=null; } //关闭执行 if(stmt!=null){ stmt.close(); stmt=null; } if(connection!=null){ connection.close(); connection=null; } }catch(SQLException e){ e.printStackTrace(); } } }
传统JDBC弊端
-
JDBC 底层没有用连接池,操作数据库需要频繁的创建和关闭连接,消耗很大的资源;
-
原生的 JDBC 代码在 Java 中,一旦需要修改 SQL,Java 需要整体编译,不利于系统维护;
-
使用 PreparedStatement 预编译的话,对变量进行设置 1、2、3 等数字,这样的序号不利于维护;
-
返回 result 结果集也需要硬编码。
思考
拿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源码解析之怎么获取数据源这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
文章标题:MyBatis3源码解析之怎么获取数据源,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/27070