h2database源码浅析:SQL语句的执行

最近想好好了解一下数据库的原理,下载了h2database的源码,准备好好看看。此过程的一些想法,暂且记下来,权当做读码笔记吧!

为了调试准备的测试用例:

	@Test
	public void testExternalDb() throws Exception
	{
		Class.forName("org.h2.Driver");
		Connection conn = DriverManager.getConnection("jdbc:h2:./testdb", "sa", "");
		// add application code here
		Statement stmt = conn.createStatement();
		stmt.executeUpdate("DROP TABLE TEST IF EXISTS");
		stmt.executeUpdate("CREATE TABLE TEST(ID INT PRIMARY KEY,NAME VARCHAR(255));");
		stmt.executeUpdate("INSERT INTO TEST VALUES(100, 'Damn,World');");
		stmt.executeUpdate("INSERT INTO TEST VALUES(200, 'Hello,H2');");
		stmt.executeUpdate("INSERT INTO TEST VALUES(150, 'Hello,World');");
		ResultSet rs = stmt.executeQuery("SELECT * FROM TEST where ID>120 and NAME like 'Hello%'");
		while (rs.next())
		{
			System.out.println(rs.getInt("ID") + "," + rs.getString("NAME"));
		}
		conn.close();
	}

以下为个人的一些猜测,后面会慢慢验证:

  • h2说到底就是内存数据库,其文件版本只是内存内容的持久化,持久化在conn.close()的时候发生;
  • SQL语句会被h2解析成Prepared对象,然后再调用它的update()方法,其中:
    • DDL会编译成DefineCommand
    • DML会编译成Query, Update, Delete等对象
  • 作为例子,CreateTable是DefineCommand的一个派生类:
  • Query有2个派生类:Select和SelectUnion
  • Select.query()代码如下:
    		while (topTableFilter.next())
    		{
    			setCurrentRowNumber(rowNumber + 1);
    			if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session)))
    			{
    				Value[] row = new Value[columnCount];
    				for (int i = 0; i < columnCount; i++)
    				{
    					Expression expr = expressions.get(i);
    					row[i] = expr.getValue(session);
    				}
    
    				//...
    				result.addRow(row);
    				rowNumber++;
    				//...
    			}
    		}


  • 可以看到,Select包含一个TableFilter,TableFilter表示待查询的表,它同时包含一个indexConditions,用以实现index过滤:

  • TableFilter.next()会调用IndexCursor.next(),IndexCursor是根据index得到的记录迭代器,其中find()方法相当于初始化,如针对ID>120会计算出firstRow指向{ID=150}这条记录;
  • TableFilter可以理解成一级过滤(根据索引进行过滤),condition可以理解成二级过滤;
  • condition的类型是Condition,测试用例里的查询会表示成一个ConditionAndOr对象;
  • LocalResult对应于一个查询结果的cache(难道不是延迟加载???),保存了所有的rows,并提供next()方法;
  • Select.query()方法会将查询结果写入LocalResult中,并返回该LocalResult;
  • JdbcStatement会将LocalResult包装成一个JdbcResultSet,返回给JDBC客户端;
    public class JdbcResultSet extends TraceObject implements ResultSet
    {
    	//...
    	public boolean next() throws SQLException
    	{
    		try
    		{
    			debugCodeCall("next");
    			checkClosed();
    			return nextRow();
    		}
    		catch (Exception e)
    		{
    			throw logAndConvert(e);
    		}
    	}
    	
    	private boolean nextRow()
    	{
    		boolean next = result.next();
    		if (!next && !scrollable)
    		{
    			result.close();
    		}
    		return next;
    	}
    	
    	//...
    }	


posted on 2015-01-02 22:47  白乔  阅读(1645)  评论(0编辑  收藏  举报

导航