随笔-23  评论-6  文章-1  trackbacks-0
 

打算到上海浙江一带去放松,解决工作上的压力。现在是去不成了,国庆4天假,广州不是放松的好地方。白云山还算可以一去,只好改去珠海玩两天,吃点海鲜补偿补偿了

posted @ 2005-10-01 12:59 ceaboat 阅读(414) | 评论 (0)编辑 收藏
WASD支持热启动,修改代码保存服务器进行实时更新,CachedRowSet crs = new CachedRowSetImpl();缓存数据集出异常。服务器热启动与缓存机制之间有冲突。
posted @ 2005-10-01 12:54 ceaboat 阅读(434) | 评论 (0)编辑 收藏

                                                          测试源代码

CapabilityForConnection 主运行程序,读取配置文件init.properties、reference.properties初始化参数。调用POOLTEST(一次完整的测试用例),计算其平均时间与使用连接数

package com.cea.repository.test;

import
 org.apache.commons.logging.LogFactory;
import
 org.apache.commons.logging.Log;
import
 java.util.Properties;
import
 java.io.FileInputStream;
import
 java.io.InputStream;

public class
 CapabilityForConnection {
    
private static Log log = LogFactory.getLog(CapabilityForConnection.class
);
    
/**

     * 计算一次测试所消耗的时间
     
*/
    
public static long times = 0;
    
/**

     * 连接数
     
*/
    
public static long psize = 0;

    
public static void main(String[] args) throws
 Exception {
        
/**

         * 运行的次数
         
*/
        
int size = 1;
        
/**

         * 见POOLTEST说明
         
*/
        
int execsum = 0;
        
/**

         * 见POOLTEST说明
         
*/
        
int opencon = 0;
        
/**

         * execsum对应properties的命名
         
*/
        String execs 
= null;
        
/**

         * opencon对应properties的命名
         
*/
        String openc 
= null;

        
long sumtime = 0
;
        Properties prop 
= initProperty("reference.properties"
);
        Properties init 
= initProperty("init.properties"
);

        
if (init.size() > 0
) {
            Object o 
= init.get("init"
);
            size 
=
 Integer.parseInt(o.toString());
            execs 
= init.get("name0"
).toString();
            openc 
= init.get("name1"
).toString();
        }

        
for (int i = 0; i < prop.size() / 2; i++
) {
            execsum 
= Integer.parseInt(prop.getProperty(execs +
 i).toString());
            opencon 
= Integer.parseInt(prop.getProperty(openc +
 i).toString());
            sumtime 
= 0
;
            psize 
= 0
;
            log.info(
"" + (i + 1+ "组数据:"
);
            log.info(
"并发应用数:" + execsum + " 模拟连接数:" +
 opencon);

            String[] reference 
= {"" + execsum, "" +
 opencon};
            
for (int j = 0; j < size; j++
) {
                times 
= 0
;
                PoolTest.main(reference);
                sumtime 
+=
 times;
            }
            log.info(
"" + (i + 1+ "组数据共执行" + size + "次;平均耗时为:" +

                     sumtime 
/ (size * execsum) + "毫秒");
            log.info(
"平均使用" + psize / size + "个连接"
);

        }
    }

    
private static Properties initProperty(String filename) throws
 Exception {
        InputStream is 
= new
 FileInputStream(filename);
        Properties prop 
= new
 Properties();
        prop.load(is);
        
return
 prop;

    }
}

POOLTEST计算一次完整过程耗时,统计消耗的连接
package com.cea.repository.test;

import
 com.cea.repository.test.testdata.MainExecute;
import
 java.util.HashMap;
import
 java.util.Map;
import
 com.cea.repository.connection.PoolSupper;
import
 org.apache.commons.logging.LogFactory;
import
 org.apache.commons.logging.Log;
/**

 *
 * 

Title: 连接池性能测试


 *
 * 

Description: 测试不合理的利用连接对WEB应用所造成影响.


 *
 * 

Copyright: Copyright (c) 2005


 *
 * 

Company: 


 *
 * 
@author 小舟
 * 
@version
 1.0
 
*/

public class PoolTest extends Thread {
    
private static Log log = LogFactory.getLog(PoolTest.class
);
    
/**

     * 并发执行MainExecute的数量
     
*/
    
private static int EXECUTESUM = 35;
    
/**

     * 一次MainExecute执行所请求的连接数
     
*/
    
public static int CONNECTIONS = 3;
    
/**

     * 记录所使用的连接
     
*/
    
public static Map poolTestMap = new HashMap();
    
/**

     * 第sum次执行MainExecute所需要的时间
     
*/
    
public int sum = 0;

    
public void
 run() {
        
try
 {
            
long s =
 System.currentTimeMillis();
            com.cea.repository.test.testdata.MainExecute.main(
null
);
            
long t = System.currentTimeMillis() -
 s;
            CapabilityForConnection.times 
+=
t;
//
            if(CapabilityForConnection.times < t){
//
                CapabilityForConnection.times = t;
//
            }

//
            log.info("time" + (++sum) + ":" +
//                               (System.currentTimeMillis() - s));

        } catch (Exception ex) {
        }
    }

    
public static void main(String[] args) throws
 Exception {
        
if(args!= null && args.length>1
){
            EXECUTESUM 
= Integer.parseInt(args[0
]);
            CONNECTIONS 
= Integer.parseInt(args[1
]);
        }

        PoolSupper.initPool();
        startExec(EXECUTESUM);
        
//设定足够长的时间等待所有程序执行完,得到准确的并发执行所消耗的时间

        try {
            Thread.sleep(
6000
);
        } 
catch
 (InterruptedException ex) {
            ex.printStackTrace();
        }
        log.info(
"运行平均耗时:" + CapabilityForConnection.times/
EXECUTESUM);
        
//如果条件成立,证明连接没有被回收,只要存在一个相同的,就证明连接被重复利用了

        CapabilityForConnection.psize +=poolTestMap.size();
        
if (poolTestMap.size() ==
 EXECUTESUM) {
            log.info(
"不存在重复使用的连接,共创建" + poolTestMap.size()+ "个连接"
 );
        } 
else
 {
            log.info(
"共使用" + poolTestMap.size()+ "个连接"
 );
        }
        clear();
    }

    
private static void startExec(int
 EXECUTESUM) {
        
int i = 0
;
        
while (i <
 EXECUTESUM) {
            
if (i++ <
 EXECUTESUM) {
                
try
 {
                    
new
 PoolTest().start();
                } 
catch
 (Exception ex2) {
                }
            }
        }
    }
    
private static void
 clear() {
        poolTestMap 
= new
 HashMap();
    }


}

简单的不能再简单的测试代码:
package com.cea.repository.test.testdata;

import
 com.cea.repository.connection.drive.ConnectionFactory;
import
 java.sql.Connection;
import
 java.sql.Statement;
import
 java.sql.ResultSet;
import
 java.sql.PreparedStatement;
import
 java.util.HashMap;
import
 java.util.Map;
import
 java.util.List;
import
 java.util.ArrayList;
import
 com.cea.repository.test.PoolTest;
import
 com.cea.repository.connection.poolpository.PoolFactory;

/**

 * 
 * 

Title: 


 * 

Description: 


 * 

Copyright: Copyright (c) 2004


 * 

Company: cea


 * 
@author 小舟
 * 
@version
 1.0
 
*/

public class MainExecute {
    
public static void main(String[] args) throws
 Exception {
       testConnection();
    }

    
static void testConnection() throws
 Exception {
        
for (int i = 0; i < PoolTest.CONNECTIONS; i++
) {
            Connection con 
=
 PoolFactory.newInstance();
            
//这里的改变直接影响连接的复用

            Thread.sleep(50);
            PoolTest.poolTestMap.put(con.toString(), 
""
);
            con.close();
        }
    }

}

三个配置文件的内容:
init.properties文件
#运行的次数
init
=5

#并发执行MainExecute的数量所匹配的名字
name0
=execsum
#一次MainExecute执行所请求的连接数所匹配的名字
name1
=opencon

reference.properties文件
#过滤数据
execsum0
=10

opencon0
=1
#第一次测试数据
execsum1
=100
opencon1
=6
#第二次测试数据
execsum2
=85
opencon2
=9
#第三次测试数据
execsum3
=140
opencon3
=3

最后一个是pool-config.xml数据源配置:
xml version="1.0" encoding="GB2312"?>
<DataResources>
  
<ResourceParams dateIndentity="boat1">
    
<defaultAutoCommit>falsedefaultAutoCommit>
    
<initialSize>30initialSize>
    
<maxActive>40maxActive>
    
<minIdle>0minIdle>
    
<maxIdle>18maxIdle>
    
<maxWait>10000maxWait>
    
<username>forumusername>
    
<password>kingpassword>
    
<driverClassName>oracle.jdbc.driver.OracleDriverdriverClassName>
    
<url>jdbc:oracle:thin:@192.168.1.3:1521:gzesturl>
    
<removeAbandoned>trueremoveAbandoned>
    
<removeAbandonedTimeout>10removeAbandonedTimeout>
    
<logAbandoned>truelogAbandoned>
  
ResourceParams>
DataResources>
posted @ 2005-09-26 22:36 ceaboat 阅读(1645) | 评论 (0)编辑 收藏

         影响性能的测试报告(数据库版)

引言

如需转载,请与笔者联系

 

前提:项目组里无用到SPRING进行事务的管理。项目里以功能划分到每个人手里,

形成了BODAOACTIONVIEW都是单人负责。在DAO中每个动作都以

      封闭式的形式存在。

问题:造成事务的不连贯性。功能是做出来了,性能问题迟早暴露。

测试:主要针对程序频繁请求数据库连接对WEB应用所造成影响做一个测试。

 

 

先做必要的说明,一步步引入正题,先从性能瓶颈开始:

性能瓶颈

所有的应用程序都存在性能瓶颈,为了提高应用程序的性能,就要尽可能的减少程序的瓶颈。以下是在JAVA程序中经常存在的性能瓶颈。

pingjing.jpg
了解了这些瓶颈后,就可以有针对性的减少这些瓶颈,从而提高JAVA应用程序的性能

 

数据库连接池工作原理

关于连接池的实现原理测试方案:

经过资料的收集与APACHE DBCP里连接池的查阅,对现有的连接池工作

原理有两种方式:

1.        数据库预先设置配置好的连接数。待得到用户请求连接,传出一个连接,而后为了保持供应数再提前创建连接,即提前预备连接数供请求。比如:

5个通行道代表最大激活的连接数,最小2个闲置连接数。也就是说连接池里始终预备了2个可随时提供的连接,连接的创建开销是比较大的,连接池的存在就是了能够最小化的解决创建所等待的时间。

  1            O

  2            O

  3            *

  4            *

  5            *

  如上图,当1分配出去时由于池中连接数剩一个,为保持最小闲置,会自动创建一个新的连接以防止再次请求等待创建的时间。这样确实减少了等待的时间,但是数据库创建的开销方面并未得到解决。如果把1-5比喻成汽车,那么这种情况下每量车都是一次性使用。1被请求后下一个连接将是6来接替。那么如何能够重复利用1减少数据库开销。于是引出第二种方式。

 

2.        回收使用完后的连接,放回到池中进行循环利用。这么做必须能保证2

   .  使连接能够保持有效的回收。

   .  约束使用者使用释放的动作,而不是直接把连接close.

 

本人使用的是APACHE DBCPBasicDataSource的连接池基本实现,

经过代码与测试结果显示,其工作方式是基于二的。

 

BasicDataSource测试用例

请看测试用例

测试结果:


2组数据:

并发应用数:100 模拟连接数:6

运行平均耗时:2956

共使用51个连接

运行平均耗时:3391

2共使用52个连接

运行平均耗时:2616

共使用47个连接

运行平均耗时:3377

共使用41个连接

运行平均耗时:3673

共使用46个连接

2组数据共执行5;平均耗时为:3229毫秒

平均使用47个连接

 

3组数据:

并发应用数:85 模拟连接数:9

运行平均耗时:4830

共使用53个连接

运行平均耗时:3247

共使用49个连接

运行平均耗时:4116

共使用40个连接

运行平均耗时:4070

共使用43个连接

运行平均耗时:4053

共使用54个连接

3组数据共执行5;平均耗时为:4063毫秒

平均使用47个连接

 

4组数据:

并发应用数:140 模拟连接数:3

运行平均耗时:2076

共使用47个连接

运行平均耗时:3104

共使用51个连接

运行平均耗时:2048

共使用43个连接

运行平均耗时:2421

共使用50个连接

运行平均耗时:2751

共使用50个连接

4组数据共执行5;平均耗时为:2480毫秒

平均使用48个连接

 

每次测试的结果都可能不同,但是所得到的结论是一致的。数据显示不合理的请求使用连接严重的影响应用所能承受的并发数量,响应的时间也因此受到影响。

 

目前普遍存在的问题

没有把事务控制好,一般会出现以下的情况:

事务(){

  流程1();

  流程2();

}

可以看出流程12里都是单独创建连接,并在自己的流程里完成操作。

如果在流程2里出现异常,那么流程1所做的操作是不可恢复的。

如果能控制在事务范围内,如:

事务(){

  Connection con;

  流程1(con);

  流程2(con);

  con.close();

}

那么数据库少提供一个连接,事务的完成性也得到体现。在并发数量大的时候,

效率上就有非常明显的区别。

解决方案

1.  尽量保持少的请求

DAO中有update()方法,则应再扩展一个方法update(Connection conn)

在业务逻辑事务里调用update(Connection conn),一般情况下调用update()

2.  对于数据不变的情况采用缓存技术,或部分缓存技术。

      可参照一些相关的开源的项目(JIVE)。

posted @ 2005-09-25 17:21 ceaboat 阅读(1658) | 评论 (4)编辑 收藏
把ent.slip放入\Borland\JBuilder2006\license里
posted @ 2005-09-24 13:45 ceaboat 阅读(808) | 评论 (2)编辑 收藏

1.运行环境:
JDK,ORACLE9i以上,CASTOR包。建议使用JBUILDE
工具进行开发
2.使用环境:
采用ORM(关系对象映射)操作数据库数据,适用于Application与WEB方式下的开发。

3.功能:
    提供查询,更新,删除,插入(没实现主键自动生成),(分页暂时没实现)。4.使用步骤:
首先在数据库建立一个cat表,字段为cat_id;name;sex;weight;类型1,4为数字型,2,
3为字符串型。

其次建立两个配置文件(由自己定义文件名称):
repository.xml配置信息:
<?xml version="1.0" encoding="UTF-8"?>
<Repository>
 <TableDesc execid="CAT" identifyField="CAT_ID">
  <table>CAT</table>
  <condition />
 <FieldDesc name="CAT_ID" fieldType="java.lang.String" >
  <title>CAT_ID</title>
  </FieldDesc>
 <FieldDesc name="NAME" fieldType="java.lang.String" >
  <title>NAME</title>
  </FieldDesc>
 <FieldDesc name="SEX" fieldType="java.lang.String" >
  <title>SEX</title>
  </FieldDesc>
 <FieldDesc name="WEIGHT" fieldType="java.lang.Long" >
  <title>WEIGHT</title>
  </FieldDesc>
  </TableDesc>
</Repository>
配置文件的设计说明如下:
TableDesc 表示一个表的声明。
Execid 是类名一般情况下最好和表名一致(容易找到对应关系),但是不允许有下划线出现。注意这个类名不是全路径。
DentifyField 表中的主键,如果是复合主键则以逗号相隔开
Table 数据库表名
<FieldDesc name="SEX" fieldType="java.lang.String" >
  <title>SEX</title>
  </FieldDesc>
这里是表中字段的描述,name是字段名。 fieldType 是数据库字段对
应java中的类型,只有4中类型可填充:java.lang.String,
java.lang.Long, java.util.Date, java.lang.Double
title可要可不要.如果存在多个表,那么就在</TableDesc>和
</Repository>之间加入表描述。

pool-config.xml配置信息:
<?xml version="1.0" encoding="GB2312"?>
<ResourceParams>
<maxActive>10</maxActive>
<maxIdle>5</maxIdle>
<maxWait>10000</maxWait>
<username>test</username>
<password>test</password>
<driverClassName>oracle.jdbc.driver.OracleDriver</driverClassName>
<url>jdbc:oracle:thin:@192.168.0.90:1521:forecast</url>
<removeAbandoned>true</removeAbandoned>
<removeAbandonedTimeout>60</removeAbandonedTimeout>
<logAbandoned>true</logAbandoned>
</ResourceParams>
把上述信息保存为XML文件。对这个文件不多做说明了。

确定两个文件已经存在,接下来就是要创建表CAT。
还有表所对应的BEAN。
下面是我在Hibernate的一个例子中建立的VO。(借用)
package com.cea.boat.dao;
  import java.util.*;
  public class Cat implements Cloneable  {
    //Declare Field
    private java.lang.String  catId;
    private java.lang.String  name;
    private java.lang.String  sex;
    private java.lang.Long  weight;
    //Get Method
    public java.lang.String getCatId() {
       return catId;
    }
    public java.lang.String getName() {
       return name;
    }
    public java.lang.String getSex() {
       return sex;
    }
    public java.lang.Long getWeight() {
       return weight;
    }
    //Set Method
    public void setCatId(java.lang.String catId) {
       this.catId=catId;
    }
    public void setName(java.lang.String name) {
       this.name=name;
    }
    public void setSex(java.lang.String sex) {
       this.sex=sex;
    }
    public void setWeight(java.lang.Long weight) {
       this.weight=weight;
    }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    }
    catch (CloneNotSupportedException ex) {
      System.out.println(o);
    }
    return o;
  }
  public boolean equals(Object obj) {
    Cat o = (Cat)obj;
    boolean result = true
        && (catId == o.catId || catId.equals(o.catId))
        && (name == o.name || name.equals(o.name))
        && (sex == o.sex || sex.equals(o.sex))
        && (weight == o.weight || weight.equals(o.weight))
    ;
    return result;
  }
  }
到此已经完成了该做的事了,下面是一个使用的例子。

l查询方式:
例子:
Void testQuery() throws Exception{
    {
System.setProperty(Const.RUN_KEY, Const.POOL_FACTORY_KEY);
      System.setProperty(Const.CONFIG_PATH,
                         "E:/project/CEAConnection/pool-config.xml");
      System.setProperty(Const.REPOSITORY_CONFIG_PATH,
                         "E:/project/CEAConnection/repository.xml");
}

ConnectionManage connectionManage = new ConnectionManage();
 connectionManage.activity("com.cea.boat.dao.Cat cat");
  
   Query Query=connectionManage.createQuery(“cat. Catid=’1’ ”);
    while (Query.hasNext()) {
      Object[] objects = Query.next();
      Cat cat = (Cat) objects[0];
    }
 connectionManage.close();
}
说明:
在WEB中使用只需要在网站启动时声明一次即可。
{
//指明使用连接池
System.setProperty(Const.RUN_KEY, Const.POOL_FACTORY_KEY);
//连接池参数配置文件
      System.setProperty(Const.CONFIG_PATH,
                         "E:/project/CEAConnection/pool-config.xml");
//配置文件指定
      System.setProperty(Const.REPOSITORY_CONFIG_PATH,
                         "E:/project/CEAConnection/repository.xml");
}

   声明一个连接管理者,管理数据库资源,事务的起始,它的生命周期最好是在一个事务结束就完结,当然你也可以在这个事务完结时继续用这个实例,来创建下一个事务的开始。不建议如此使用。
    ConnectionManage DataManage = new ConnectionManage();
   
激活要使用类(在配置中必须有Cat),类名为全路径如果要使用多个对象,则对象间要用逗号相隔开
connectionManage.activity("com.cea.boat.dao.Cat cat");

这里只需要给出SQL查询条件比如SQL中是select * from cat cat where cat.Catid=‘1’那么 select * from cat cat where 这里后台已经帮你完成,你需要做的就是把条件完成,如果没有条件则为空.
Query Query = connectionManage.createQuery(“cat. Catid=’1’ ”);


   Query.hasNext()的作用相当于resultset.next()查看是否还存在记录,Query.next()返回一个对象数组这里如果activity的是多个对象,那么objects里会顺序的存储相应的对象实例,使用的时候强制转化就可以了。
while (Query.hasNext()) {
      Object[] objects = Query.next();
      Cat cat = (Cat) objects[0];
  }

使用完毕,释放使用的数据库资源
 connectionManage.close();

l新增方式:
  由于没有主键自动生成,因此主键暂时只能由自己来维护,要保证catid为111的在表里不存在,否则会出现异常。
Void testInsert() throws Exception{
Cat cat = new Cat();
cat. setCatId(“111”);
    cat. SetSex(“F”);
    cat. setName(“catm”);
    ConnectionManage cm = new ConnectionManage();
    cm.create(cat);
    cm.commit();
cm.close();
}

l更新方式:
表里已经存在catid为111的猫,否则查不到这条记录就更新不了信息
Void testUpdate() throws Exception{
Cat cat = new Cat();
cat. setCatId(“111”);
    cat. SetSex(“F”);
    cat. setName(“catmm”);
    ConnectionManage cm = new ConnectionManage();
    cm.update(cat);
    cm.commit();
cm.close();
}

l删除方式:
删除方式比较简单,只要给出对象,并且主键值不为空,就可以删除表中记录。
Void testDelete() throws Exception{
Cat cat = new Cat();
cat. setCatId(“111”);
    ConnectionManage cm = new ConnectionManage();
    cm.delete(cat);
    cm.commit();
cm.close();
}

posted @ 2005-09-15 23:41 ceaboat 阅读(423) | 评论 (0)编辑 收藏
仅列出标题
共2页: 上一页 1 2