有三种产生TableView的方式: 1. CREATE VIEW语句 如: CREATE OR REPLACE FORCE VIEW IF NOT EXISTS my_view COMMENT IS 'my view'(f1,f2) AS SELECT id,name FROM CreateViewTest 2. 嵌入在FROM中的临时视图 如: select id,name from (select id,name from CreateViewTest) 3. WITH RECURSIVE语句 如: WITH RECURSIVE my_tmp_table(f1,f2) AS (select id,name from CreateViewTest UNION ALL select 1, 2) select f1, f2 from my_tmp_table RECURSIVE这个关键字是可选的 只有2可以带Parameters,它是通过这个方法调用: org.h2.table.TableView.createTempView(Session, User, String, Query, Query) 只有3的recursive是true TableView构造函数 => init => ViewIndex => initColumnsAndTables => removeViewFromTables => compileViewQuery //重新对select语句进行解析和prepare => setColumns => addViewToTables removeViewFromTables和addViewToTables相对应,把view自身加到相关的Table中 一个view可以与多个table相关,取决于select语句中涉及的表个数: 对于以下例子: CREATE OR REPLACE FORCE VIEW my_view (f1,f2) AS SELECT t1.f1, t2.f2 FROM t1, t2? 那么my_view就涉及两个表t1,t2 removeViewFromTables就是从t1,t2中把my_view删除, 而addViewToTables就是把my_view加到t1,t2中。 为企么要有removeViewFromTables和addViewToTables呢, 因为init方法在OR REPLACE时也会通过TableView类的replace方法调用,所以在t1,t2中已有my_view了, 但是CREATE VIEW语句会变,所以此时的my_view对象有可能是旧的,所以要删除 initColumnsAndTables就是根据select语句定义view中有哪些字段,这些字段的类型跟select中的select表达式列表中的对应表达式一样 //select字段个数比view字段多的情况,多出来的按select字段原来的算 //这里实际是f1、name sql = "CREATE OR REPLACE FORCE VIEW my_view COMMENT IS 'my view'(f1) " // + "AS SELECT id,name FROM CreateViewTest"; //select字段个数比view字段少的情况,view中少的字段被忽略 //这里实际是f1,而f2被忽略了,也不提示错误 sql = "CREATE OR REPLACE FORCE VIEW my_view COMMENT IS 'my view'(f1, f2) " // + "AS SELECT id FROM CreateViewTest"; //不管加不加FORCE,跟上面也一样 sql = "CREATE OR REPLACE VIEW my_view COMMENT IS 'my view'(f1, f2) " // + "AS SELECT id FROM CreateViewTest"; 虽然执行了两次initColumnsAndTables,但是init中还建立了ViewIndex 所以这里是必须调用init的 replace => init => ViewIndex => initColumnsAndTables => removeViewFromTables => compileViewQuery //重新对select语句进行解析和prepare => setColumns => addViewToTables => recompile => compileViewQuery => getViews => initColumnsAndTables => getViews中得到的依赖于当前view的都需要recompile