问题的提出: 一般情况下,我们采用分页技术来解决大数据量加载的问题,这也是最好的办法。但是在有的项目中会遇到一次加载"万单位级别"数据的需求。尽管这是很糟糕的做法,即耗资源、加载速度又慢,但用户明指明了这样的需求,不这么做还不行。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

解决方法: 采用 SWT 中的虚拟表格技术来创建拥有大数据量的表格,解决加载速度让人难以忍受的问题,提升加载效率。

         为了充分的说明问题,本文通过对比常规方法和虚拟表格技术加载 2 万条数据所需的时间,来说明虚拟表格在加载大数据量时的优越表现。

 

第一步:准备数据

1.  首先建立所需的数据表

 

create table user (id int(10) primary key auto_increment, name1 varchar(20) , name2 varchar(20) , name3 varchar(20) , name4 varchar(20)) type=innodb;

 

2. 插入数据 (写测试的目的一般带有破坏性,我插了 2 万条)

 

  for ( int i=0;i<20000;i++)

            {

            String s = "chengang" ;

            sm.executeUpdate( "insert into test_table (name0,name1,name2,name3) values ('" + s+1 +i + "','" + s +2+i + "','" + s +3+i + "','" + s +4+i + "')" );

            }

 

3 .创建一个 DAO 文件,用来处理插入和获得数据:

 

ConnDAO.java,详细内容请参看源文件

// 按照给定的 sql 进行数据库查询

// 取出数据后,赋值个 Vector ,并返回

  public Vector executeQuery(String sql)

 {

    ResultSet rs = null;

    Vector vResult = new Vector();

    try

   {

        Class.forName(driver);

        con = DriverManager.getConnection(dburl,userName,password);

        stmt = con.createStatement();

        rs = stmt.executeQuery(sql);

        ResultSetMetaData rsmd = rs.getMetaData();

        int  numCols = rsmd.getColumnCount();

         while (rs.next())

              {

                     String strTempArray[] = new String[numCols];

          for(int i = 1; i <= numCols; i++)

                     {

                  /* 将存储过程得到的每个字段赋值到字符串数组,并将其做为对象加入到 vector 类中返回 */

            strTempArray[i - 1] = rs.getString(i);

                     }

                     vResult.addElement(strTempArray);

              }

       

    }catch(Exception e)

    {

        System.out.println("Query Error!!!!!!!!!");

    }

    return vResult;

  }

}

 

第二步:创建测试文件

 
在开始之前,请你确认正确安装了 SWT Designer ,创建一个基于 SWT/JFS 的项目(不是必须,但这样可以方便使用可视化编辑,当然你也可以直接编写代码)。

 
 1 .为了与虚拟表格进行对比,我们首先用普通 Table 加载这 2 万条数据。

 

HelloWorld_Common.java

package edu.bjtu.zhao.demo;

//import 引入相关的类,具体可以参考本文的源文件

 

public class HelloWorld_Common {

 

       private static Table table;

       /**

        * Launch the application

        * @param args

        */

       public static void main(String[] args) {

      

       // 为了清晰说明问题,在此省略了相关部分代码,可以参考 源代码

              table = new Table(shell, SWT.BORDER);// 注意此处与虚拟表格设置的不同

             

              table.setBounds(40, 30, 723, 290);

             

// 此处省略了创建 5 列的代码,

              try  

              {  

//                   获得数据表格数据

                       ConnDAO dao = new ConnDAO();

                       String ss= "select * from test_table";//SendTable 为表名

                      final Vector  vResult = dao.executeQuery(ss);

                      for (int i=0;i<vResult.size();i++)

                      {

                           // 因为条目都是直接创建的,这样初始化的过程就相当慢

TableItem  item = new TableItem(table,SWT.NONE);   

                             item.setText((String[])vResult.get(i)); 

                      }

              }catch(Exception exception)  

              {  

                  exception.printStackTrace();  

              }

       }

}

 
   写完程序后,你可以直接在 Eclipse 中运行,运行结果如下图所示,当然不要忘记适当的计算一下时间 , 我的电脑的配置是:

Intel 双核 1.73GHz <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /> 512M 内存,

用的是: jdk1.5.0_06   MySQLversion: 4.0.14-nt

我的运行时间约是: 10 秒。

我想这样的速度,你的客户是不能忍受的,而且创建了那么多的 Item ,如果用户不看,且不是造成了严重的资源浪费。

 
2 .做了这么多准备工作,下面开始令人兴奋的虚拟表格之旅吧。

 
创建 HelloWorld_Virtual.java

package edu.bjtu.zhao.demo;

 

//import ……具体的包,可以参见附件中的源代码

 

public class HelloWorld_Virtual {

 

       private static Table table;

      

       /**

        * Launch the application

        * @param args

        */

       public static void main(String[] args) {

              //final Vector vResult = new Vector();

              final Display display = Display.getDefault();

             

              final Shell shell = new Shell();//shell 是主程序窗口

             

              shell.setSize(808, 375);// 设置窗体初始化大小

              shell.setText("SWT Application");// 设置窗体名称

              shell.open();// 主程序打开

/ 创建表格 //

              table = new Table(shell, SWT.BORDER| SWT.VIRTUAL);// 注意此处的设置

              table.setLinesVisible(true);

              table.setHeaderVisible(true);

              table.setBounds(40, 30, 723, 290);

/// 创建表格四列

              final TableColumn newColumnTableColumn = new TableColumn(table, SWT.NONE);

              newColumnTableColumn.setWidth(100);

              newColumnTableColumn.setText("id");

             

       /// 同样的方法创建另外 4

             

             

           // 获得数据表格数据

                ConnDAO dao = new ConnDAO();

                String ss= "select * from test_table";//SendTable 为表名

               final Vector  vResult = dao.executeQuery(ss);

               

              / 设置监听 /

               

              /* table.addListener(SWT.SetData, new Listener() { 

                   public void handleEvent(Event event) { 

                      TableItem item = (TableItem)event.item; 

                      int index = event.index; 

                      item.setText((String[])vResult.get(index)); 

                   }    

               });  */

        // 另一种方式实现虚拟表格 ///

         final int PAGE_SIZE = 100; 

             table.addListener (SWT.SetData, new Listener () {

                 public void handleEvent (Event event) {

                     TableItem item = (TableItem) event.item;

                     int index = event.index;

                     int page = index / PAGE_SIZE;

                     int start = page * PAGE_SIZE;

                     int end = start + PAGE_SIZE;

                     end = Math.min (end, table.getItemCount ());

                     for (int i = start; i < end; i++) {

                        item = table.getItem (i);

                       item.setText ((String[])vResult.get(i));

             }

                 }

              });

           // 设计总记录数,便于滚动条计算 //      

              table.setItemCount(vResult.size()); 

 

              shell.layout();// 主程序布置

              while (!shell.isDisposed()) {// 如果主程序没有关闭,这一直循环

                     if (!display.readAndDispatch())// 如果不忙

                            display.sleep();// 休眠

              }

       }

}

 
   呵呵, run 一下吧,我测试的结果,算上绘制界面的时间也就 1 秒左右, 如果在界面上做个查询,再来显示的话,基本“万单位”级别的数据也能做到即时加载啦

    在源代码中我已经做了较详细的注释,因为本文主要以实际操作为主,所以没有对具体的方法进行深入的分析。另外一个原因就是,现在网上有一篇文章《Virtual Tables and Trees》对虚拟表格和树做了较深入的分析,我不再重复他人的劳动,你可以参考一下。网上有这篇文章的中文版,不过如果你打算在IT界混的话,还是建议你读英文吧。

 

参考文献 Virtual Tables and Trees<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /> June 2006  by Beatriz Iaderoza (IBM Ottawa Lab) and Grant Gayed (IBM)