读书人

hsqldb源码分析起步调试

发布时间: 2013-01-23 10:44:49 作者: rapoo

hsqldb源码分析启动调试

hsqldb是java版的简化数据库,代码量比较少,对于学习数据库的设计是一个比较好的选择,

对于derby代码量比较大,mysql c++更复杂,所以就通过学习hsqldb来学习数据库的设计。

在这里可以下载到源码http://hsqldb.org/,源码包下org.hsqldb.test有很多的测试类,大家可以从这里开始调试学习hsqldb。

HyperSQL 数据库叫catalog,根据数据库存储方式不同分为几种:

? mem: stored entirely in RAM - without any persistence beyond the JVM process's life
? file: stored in filesystem files

? res: stored in a Java resource, such as a Jar and always read-only

客户端可以通过连接串不同指定不同的存储格式

 Connection c = DriverManager.getConnection("jdbc:hsqldb:file:testdb", "SA", "");Connection c = DriverManager.getConnection("jdbc:hsqldb:file:/opt/db/testdb", "SA", "");file:数据保存在文件 Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:mymemdb", "SA", "");mem表示数据库只保存在内存  Connection c = DriverManager.getConnection("jdbc:hsqldb:res:org.my.path.resdb", "SA", ""); res表示压缩保存classpath java或者zip包中,内存解压使用

启动hyperSQL的服务器模式HyperSQL HSQL Server 可以使用参数--help查看参数选项,下面是打开mydb数据文件作为数据库别名为xdb,客户端就可以使用xdb数据库来连接服务器使用了。
java -cp ../lib/hsqldb.jar org.hsqldb.server.Server --database.0 file:mydb --dbname.0 xdb
HyperSQL HTTP Server http协议的服务器模式
java -cp ../lib/hsqldb.jar org.hsqldb.server.WebServer --database.0 file:mydb --dbname.0 xdb
servlet容器启动服务器HyperSQL HTTP Servlet需要在web.xml配置org/hsqldb/server/Servlet.java 这个servlet,这种模式只能支持一个数据库。客户端连接到hsql server:
 try {      Class.forName("org.hsqldb.jdbc.JDBCDriver" );  } catch (Exception e) {      System.err.println("ERROR: failed to load HSQLDB JDBC driver.");      e.printStackTrace();      return;  }
 Connection c = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost/xdb", "SA", "");如果是hsql服务器模式则用:hsql:,http则用http://  Connection c = DriverManager.getConnection("jdbc:hsqldb:http://localhost/xdb", "SA", "");使用ssl连接到hsql和 http 服务器 Connection c = DriverManager.getConnection("jdbc:hsqldb:hsqls://localhost/xdb", "SA", ""); Connection c = DriverManager.getConnection("jdbc:hsqldb:https://localhost/xdb", "SA", "");
关闭服务器:使用参数shutdown=true,最后一个连接处理完了需要关闭服务器,会对内存数据进行处理(如果是文件的,则flush到文件),这个在测试场景下用得比较多。  Connection c = DriverManager.getConnection(          "jdbc:hsqldb:file:/opt/db/testdb;shutdown=true", "SA", "");如果要重用已有的数据库,则用参数ifexists=true,如果数据库不存在,则抛异常。Connection c = DriverManager.getConnection(        "jdbc:hsqldb:file:/opt/db/testdb;ifexists=true", "SA", "");
代码分析: org.hsqldb.server类的run方法处理输入,打开数据库,建立服务器socket或者http连接,监听socket连接,每次accept一个socket连接,则使用public void handleConnection(Socket s)方法来处理该连接,每个客户端连接服务端都会生产一个线程来处理,然后在每个ServerConnection或者WebServerConnection处理每个sql的处理,后面再进一步分析sql的访问协议,以后sql语法分析,语义分析等后续逻辑。 这段代码比较简单,大家可以直接查看server类。 关键部分开始如下:
 public void handleConnection(Socket s) {        Thread   t;        Runnable r;        String   ctn;        printWithThread("handleConnection(" + s + ") entered");        if (!allowConnection(s)) {            try {                s.close();            } catch (Exception e) {}            printWithThread("allowConnection(): connection refused");            printWithThread("handleConnection() exited");            return;        }        // Maybe set up socket options, SSL        // Session tracing/callbacks, etc.        if (socketFactory != null) {            socketFactory.configureSocket(s);        }        if (serverProtocol == ServerConstants.SC_PROTOCOL_HSQL) {            r   = new ServerConnection(s, this);            ctn = ((ServerConnection) r).getConnectionThreadName();        } else {            r   = new WebServerConnection(s, (WebServer) this);            ctn = ((WebServerConnection) r).getConnectionThreadName();        }        t = new Thread(serverConnectionThreadGroup, r, ctn);        t.start();        printWithThread("handleConnection() exited");    }

从server的main函数输出参数中主要有几个:maxConnections 最大连接数限制, isSilent是否显示所有query,isRemoteOpen是否支持远程打开,不支持,isDaemon是否守护模式,acl指定访问控制权限文件路径,指定ip地址的黑白名单。acl文件格式参考http://hsqldb.org/doc/2.0/guide/listeners-chapt.html#N15C79

 * +-----------------+-------------+----------+------------------------------+ * |    OPTION       |    TYPE     | DEFAULT  |         DESCRIPTION          | * +-----------------+-------------+----------+------------------------------| * | --help          |             |          | prints this message          | * | --address       | name|number | any      | server inet address          | * | --port          | number      | 9001/544 | port at which server listens | * | --database.i    | [type]spec  | 0=test   | path of database i           | * | --dbname.i      | alias       |          | url alias for database i     | * | --silent        | true|false  | true     | false => display all queries | * | --trace         | true|false  | false    | display JDBC trace messages  | * | --tls           | true|false  | false    | TLS/SSL (secure) sockets     | * | --no_system_exit| true|false  | false    | do not issue System.exit()   | * | --remote_open   | true|false  | false    | can open databases remotely  | * | --props         | filepath    |          | file path of properties file | * +-----------------+-------------+----------+------------------------------+

    maxConnections = serverProperties.getIntegerProperty(            ServerProperties.sc_key_max_connections, 16);        JavaSystem.setLogToSystem(isTrace());        isSilent =            serverProperties.isPropertyTrue(ServerProperties.sc_key_silent);        isRemoteOpen = serverProperties.isPropertyTrue(            ServerProperties.sc_key_remote_open_db);        isDaemon =            serverProperties.isPropertyTrue(ServerProperties.sc_key_daemon);

当然openDatabase里面就是根据参数指定的database文件打开对应的数据库。

在database类的reopen方法中有几个对象,就是数据库操作相关的对象,无非就是数据库对象名称管理,权限管理,用户管理,shema管理,session管理,事务管理,日志管理,检查点管理,后续一个一个分析。

  /**     * Opens this database.  The database should be opened after construction.     * or reopened by the close(int closemode) method during a     * "shutdown compact". Closes the log if there is an error.     */    void reopen() {        boolean isNew = false;        setState(DATABASE_OPENING);        try {            nameManager    = new HsqlNameManager(this);            granteeManager = new GranteeManager(this);            userManager    = new UserManager(this);            schemaManager  = new SchemaManager(this);            persistentStoreCollection =                new PersistentStoreCollectionDatabase();            isReferentialIntegrity = true;            sessionManager         = new SessionManager(this);            collation              = collation.newDatabaseInstance();            dbInfo = DatabaseInformation.newDatabaseInformation(this);            txManager              = new TransactionManager2PL(this);            lobManager.createSchema();            sessionManager.getSysLobSession().setSchema(                SqlInvariants.LOBS_SCHEMA);            schemaManager.setSchemaChangeTimestamp();            schemaManager.createSystemTables();            // completed metadata            logger.openPersistence();            isNew = logger.isNewDatabase;            if (isNew) {                String username = urlProperties.getProperty("user", "SA");                String password = urlProperties.getProperty("password", "");                userManager.createFirstUser(username, password);                schemaManager.createPublicSchema();                lobManager.initialiseLobSpace();                logger.checkpoint(false);            }            lobManager.open();            dbInfo.setWithContent(true);            checkpointRunner = new CheckpointRunner();        } catch (Throwable e) {            logger.closePersistence(Database.CLOSEMODE_IMMEDIATELY);            logger.releaseLock();            setState(DATABASE_SHUTDOWN);            clearStructures();            DatabaseManager.removeDatabase(this);            if (!(e instanceof HsqlException)) {                e = Error.error(ErrorCode.GENERAL_ERROR, e);            }            logger.logSevereEvent("could not reopen database", e);            throw (HsqlException) e;        }        setState(DATABASE_ONLINE);    }

下一节分析handleConnection的处理

读书人网 >其他数据库

热点推荐