随笔 - 18, 文章 - 0, 评论 - 8, 引用 - 0
数据加载中……

2005年7月24日

CyclicBarrier 简单举例

一句话解释:预备~~~开始

 1 import java.util.concurrent.BrokenBarrierException;
 2 import java.util.concurrent.CyclicBarrier;
 3 
 4 import org.slf4j.Logger;
 5 import org.slf4j.LoggerFactory;
 6 
 7 public class CyclicBarrierLearn {
 8     
 9     private Logger log = LoggerFactory.getLogger(CyclicBarrierLearn.class);
10     
11     private class Work extends Thread {
12         
13         private String name;
14         private CyclicBarrier cyclicBarrier;
15         
16         public Work(String name, CyclicBarrier cyclicBarrier) {
17             this.name = name;
18             this.cyclicBarrier = cyclicBarrier;
19         }
20         
21         @Override
22         public void run() {
23             try {
24                 log.debug("thread name: " + name + " waiting work");
25                 cyclicBarrier.await();
26                 log.debug("thread name: " + name + " working");
27             } catch (InterruptedException e) {
28                 e.printStackTrace();
29             } catch (BrokenBarrierException e) {
30                 e.printStackTrace();
31             }
32             
33         }
34     }
35     
36     public void cyclicBarrier() {
37         CyclicBarrier cyclicBarrier = new CyclicBarrier(50, new Runnable() {
38             
39             @Override
40             public void run() {
41                 log.debug("let's begin work");
42             }
43         });
44         
45         for (int i = 0; i < cyclicBarrier.getParties(); i++) {
46             Work work = new Work(String.valueOf(i), cyclicBarrier);
47             work.start();
48         }
49         
50     }
51 
52     public static void main(String[] args) {
53         CyclicBarrierLearn cyclicBarrierLearn = new CyclicBarrierLearn();
54         cyclicBarrierLearn.cyclicBarrier();
55 
56     }
57 
58 }
59 

posted @ 2017-07-13 11:39 丑男 阅读(158) | 评论 (0)编辑 收藏

CountDownLatch 简单举例

一句话解释:主线程阻塞,其他线程完成后,主线程被唤醒后继续执行

 1 import java.util.Random;
 2 import java.util.concurrent.CountDownLatch;
 3 
 4 import org.slf4j.Logger;
 5 import org.slf4j.LoggerFactory;
 6 
 7 public class CountDownLatchLearn {
 8     
 9     private Logger log = LoggerFactory.getLogger(CountDownLatchLearn.class);
10     private CountDownLatch countDownLatch;
11     
12     public CountDownLatchLearn() {
13         countDownLatch = new CountDownLatch(50);
14     }
15     
16     public void countDown() {
17         Long count = countDownLatch.getCount();
18         log.debug("countDownLatch count is:" + count.toString());
19         
20         for (int i = 0; i < count; i++) {
21             Work work = new Work(String.valueOf(i), countDownLatch);
22             work.start();
23         }
24         try {
25             countDownLatch.await();
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29         log.debug("work finish!!!");
30     }
31     
32     private class Work extends Thread {
33         
34         private String name;
35         private CountDownLatch countDownLatch;
36         
37         public Work(String name, CountDownLatch countDownLatch) {
38             this.name = name;
39             this.countDownLatch = countDownLatch;
40         }
41         
42         @Override
43         public void run() {
44             Random r = new Random();
45             int sleep = r.nextInt(2000);
46             try {
47                 log.debug("thread sleep: "+ sleep);
48                 Thread.sleep(sleep);
49             } catch (InterruptedException e) {
50                 e.printStackTrace();
51             }
52             log.debug("thread: " + name + ": do work");
53             countDownLatch.countDown();
54         }
55     }
56 
57     public static void main(String[] args) {
58         System.out.println("main start!!!");
59         
60         CountDownLatchLearn countDownLatchLearn = new CountDownLatchLearn();
61         countDownLatchLearn.countDown();
62         
63         System.out.println("main end!!!");
64     }
65 
66 }

posted @ 2017-07-13 11:18 丑男 阅读(295) | 评论 (0)编辑 收藏

mysql 5.7 for windows安装过程

环境说明:

OSwindows 7 64bit Databasemysql-5.7.18-winx64 Noinstall版本

 

1. 解压Mysql安装目录

2. 编写my.ini配置文件

3. mysqld --defaults-file=../my.ini --initialize

4. ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';

5. mysql –u root –p

6. 密码在logs/*.err日志中

 
my.ini文件内容

 1 # my.ini文件内容
 2 # For advice on how to change settings please see
 3 # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
 4 # *** DO NOT EDIT THIS FILE. It's a template which will be copied to the
 5 # *** default location during install, and will be replaced if you
 6 # *** upgrade to a newer version of MySQL.
 7 
 8 [mysqld]
 9 
10 # Remove leading # and set to the amount of RAM for the most important data
11 # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
12 # innodb_buffer_pool_size = 128M
13 
14 # Remove leading # to turn on a very important data integrity option: logging
15 # changes to the binary log between backups.
16 # log_bin
17 
18 # These are commonly set, remove the # and set as required.
19 basedir=D:\\mysql-5.7.18-winx64
20 datadir=D:\\mysql-5.7.18-winx64\\data
21 # port = ..
22 # server_id = ..
23 
24 
25 # Remove leading # to set options mainly useful for reporting servers.
26 # The server defaults are faster for transactions and fast SELECTs.
27 # Adjust sizes as needed, experiment to find the optimal values.
28 # join_buffer_size = 128M
29 # sort_buffer_size = 2M
30 # read_rnd_buffer_size = 2M 
31 
32 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
33 
34 long_query_time=0.1
35 slow_query_log=on
36 slow_query_log_file=D:\\mysql-5.7.18-winx64\\logs\\mysqlslow.log
37 

posted @ 2017-07-10 00:53 丑男 阅读(174) | 评论 (0)编辑 收藏

添加用户【备份】

useradd -g 501 -s /sbin/nologin builder

posted @ 2013-05-06 17:25 丑男 阅读(109) | 评论 (0)编辑 收藏

[ZT]Java虚拟机JVM的调优参数选择

在任何一个的生产系统上线前,系统性能调优(Tuning)都是很重要的一步。通常,应用系统的软硬件的缺省值都是给开发平台(或小规模系统)设计的,用来跑生产系统几乎都无法发挥出软硬件的最佳性能。有时,系统调优前后的性能会差好几倍。另一方面,由于应用程序的开发人员通常都是针对功能作开发的,因此,开发硬件都是比生产环境要小的机器。例如,生产系统是一台8个CPU,64GB内存服务器,而开发服务器可能只有1个CPU和4GB内存。所以,在开发人员中常常不具备做性能方面测试的软硬件环境。另外,有的程序员甚至在开发时都没有考虑到多用户并发的环境,程序中存在单点瓶颈等问题。在做压力测试和调优时,往往就会发现这些关键点。

  由于应用系统是个软硬件的完整统一体,系统调优往往需要涉及硬件、网络操作系统、中间件,应用程序和数据库等方面。在调优的过程中,往往需要发现存在瓶颈的地方(也就是导致系统变慢的部分),分析原因,从而改进和确定较优的参数。

  我们在作JVM的调优前,通常先要了解运行的硬件平台,操作系统和中间件,然后针对这些情况配置相应的系统参数,在测试中不断完善参数。由于性能调优需要对系统非常了解,并且需要丰富的经验,因此不是一件容易的事情。这里介绍一些很好的参考资料,就是SPEC.org的网站。这是硬件厂商公布benchmark测试结果的地方,通常硬件厂商会把系统调到最优化才公布结果的,因此很有借鉴意义。常见和JVM有关的benchmark值主要有SPECjAppServer2004和SPECjbb2005。前者是J2EE应用服务器的性能指标,后者是服务器端Java虚拟机的性能指标。给大家介绍这个网站的目的是说大家可以参考硬件厂商给出的JVM配置,在根据自己应用环境的特点,较快的得出较好的参数。例如,这个网页给出了SUN公司T5120服务器+应用服务器9.1 +JDK1.5的SPECjAppServer2004值是8,439.36:

  http://www.spec.org/jAppServer2004/results/res2007q4/jAppServer2004-20071106-00092.html

  我们现在要关心的不是Benchmark的值(注:实际上,Sun公司的这个值是个很不错的结果),而是留意在这种环境下JVM的参数配置,可以找到一个栏目“Notes / Tuning Information”:

  JVM Options: -server -XX:+AggressiveHeap

-Xmx2560m -Xms2560m -Xmn1024m -Xss128k

-XX:PermSize=256m

-XX:+DisableExplicitGC

-XX:ParallelGCThreads=24

-XX:LargePageSizeInBytes=256m

-XX:+UseParallelOldGC

-XX:+AggressiveOpts

-DAllowManagedFieldsInDefaultFetchGroup=true

-DAllowMediatedWriteInDefaultFetchGroup=true

-XX:-UseBiasedLocking

-Dcom.sun.ejb.containers.readonly.relative.refresh.mode=true

-Dcom.sun.jts.dblogging.insertquery=insert into

txn_log_table_0 values (
? , ? , ? )

-Dcom.sun.jts.dblogging.deletequery=delete from

txn_log_table_0 where localtid
= ? and servername = ?

-Dcom.sun.jdo.spi.persistence.support.sqlstore.

MULTILEVEL_PREFETCH
=true

  那么上面那些参数是什么意思呢?上述段落中“-XX”的参数是SUN JVM的扩展选项,其中以下的这些都是和垃圾回收(GC)有关:

  -XX:PermSize=256m

-XX:+DisableExplicitGC

-XX:ParallelGCThreads=24

-XX:+UseParallelOldGC

-XX:+AggressiveHeap

  下面这个选项是选择大的内存页面:

  -XX:LargePageSizeInBytes=256m

  "-XX:+AggressiveOpts"是一些试验性优化参数,“-XX:-UseBiasedLocking”是非竞争性的同步选项。

  而选项“-Xmx2560m -Xms2560m -Xmn1024m -Xss128k”则是初始堆栈的内存值,注意-Xmx和-Xms的值是一样的,这样系统性能会较平稳些。

  至于这些参数详细代表什么意义,大家可以google一下就很容易了解。这是Sun网站上的说明,有兴趣的可以读一下: http://java.sun.com/performance/reference/whitepapers/tuning.html

  如果你的应用系统是JDK1.5,硬件是T5120,操作系统是Solaris,那么这些参数就很有借鉴意义。如果你的硬件系统不是T5120,但是使用SUN的JDK1.5 ,这些参数也是有一定参考作用。当然,最理想的是选择一个和自己的环境最近似的结果来参考。大多数软硬件的测试结果都可以在SPEC.org上找到,如果你的系统是J2EE的3层架构,可以用jAppServer2004指标,如果是纯JAVA的应用,可用jbb2005的结果:

  http://www.spec.org/jAppServer2004/

  http://www.spec.org/jbb2005/

  需要注意的是,这些调优参数只是提供了一个思路,具体是否合适你的应用还要看实测结果。

posted @ 2009-04-29 19:24 丑男 阅读(249) | 评论 (0)编辑 收藏

[转帖]Hibernate常用保存

hibernate对于对象的保存提供了太多的方法,他们之间有很多不同,这里细说一下,以便区别:
一、预备知识:
在所有之前,说明一下,对于hibernate,它的对象有三种状态,transient、persistent、detached
下边是常见的翻译办法:
transient:瞬态或者自由态
persistent:持久化状态
detached:脱管状态或者游离态
脱管状态的实例可以通过调用save()、persist()或者saveOrUpdate()方法进行持久化。
持久化实例可以通过调用 delete()变成脱管状态。通过get()或load()方法得到的实例都是持久化状态的。
脱管状态的实例可以通过调用 update()、0saveOrUpdate()、lock()或者replicate()进行持久化。
save() 和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE,而update()或merge()会引发 SQLUPDATE.对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起 SQLUPDATE.saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE
二、save 和update区别
把这一对放在第一位的原因是因为这一对是最常用的。
save的作用是把一个新的对象保存
update是把一个脱管状态的对象保存
三、update 和saveOrUpdate区别
这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update引用hibernate reference中的一段话来解释他们的使用场合和区别。
通常下面的场景会使用update()或saveOrUpdate():
程序在第一个session中加载对象
该对象被传递到表现层
对象发生了一些改动
该对象被返回到业务逻辑层
程序调用第二个session的update()方法持久这些改动
saveOrUpdate()做下面的事:
如果对象已经在本session中持久化了,不做任何事
如果另一个与本session关联的对象拥有相同的持久化标识(identifier),抛出一个异常
如果对象没有持久化标识(identifier)属性,对其调用save()
如果对象的持久标识(identifier)表明其是一个新实例化的对象,对其调用save()
如果对象是附带版本信息的(通过或) 并且版本属性的值表明其是一个新实例化的对象,save()它。
四、persist和save区别
这个是最迷离的一对,表面上看起来使用哪个都行,在hibernate reference文档中也没有明确的区分他们。
这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别)
1.persist把一个瞬态的实例持久化,但是并"不保证"标识符被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时间。
2.persist" 保证",当它在一个transaction外部被调用的时候并不触发一个Sql Insert,这个功能是很有用的,当我们通过继承Session/persistence context来封装一个长会话流程的时候,一个persist这样的函数是需要的。
3.save"不保证"第2条,它要返回标识符,所以它会立即执行Sql insert,不管是不是在transaction内部。
五、saveOrUpdateCopy,merge和update区别
首先说明merge是用来代替saveOrUpdateCopy的,然后比较update和merge,update的作用上边说了,这里说一下merge的作用。
如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例
如果session没有相应的持久实例,则尝试从数据库中加载,或创建新的持久化实例,最后返回该持久实例
用户给出的这个对象没有被关联到session上,它依旧是脱管的
重点是最后一句:
当我们使用update的时候,执行完成后,我们提供的对象A的状态变成持久化状态
但当我们使用merge的时候,执行完成,我们提供的对象A还是脱管状态,hibernate或者new了一个B,或者检索到一个持久对象,并把我们提供的对象A的所有的值拷贝到这个B,执行完成后B是持久状态,而我们提供的A还是托管状态。
六、flush和update区别
这两个的区别好理解
update操作的是在脱管状态的对象,而flush是操作的在持久状态的对象。
默认情况下,一个持久状态的对象是不需要update的,只要你更改了对象的值,等待hibernate flush就自动保存到数据库了。hibernate flush发生再几种情况下:
1.调用某些查询的时候
2.transaction commit的时候
3.手动调用flush的时候
七、lock和update区别
update是把一个已经更改过的脱管状态的对象变成持久状态
lock是把一个没有更改过的脱管状态的对象变成持久状态
对应更改一个记录的内容,两个的操作不同:
update的操作步骤是:
更改脱管的对象->调用update
lock的操作步骤是:
调用lock把对象从脱管状态变成持久状态——>更改持久状态的对象的内容——>等待flush或者手动flush

posted @ 2008-08-23 21:22 丑男 阅读(210) | 评论 (0)编辑 收藏

[转帖]Oracle执行计划解释

一.相关的概念

    Rowid的概念:rowid是一个伪列,既然是伪列,那么这个列就不是用户定义,而是系统自己给加上的。 对每个表都有一个rowid的伪列,但是表中并不物理存储ROWID列的值。不过你可以像使用其它列那样使用它,但是不能删除改列,也不能对该列的值进行 修改、插入。一旦一行数据插入数据库,则rowid在该行的生命周期内是唯一的,即即使该行产生行迁移,行的rowid也不会改变。

    Recursive SQL概念:有时为了执行用户发出的一个sql语句,oracle必须执行一些额外的语句,我们将这些额外的语句称之为''recursive calls''或''recursive sql statements''.如当一个DDL语句发出后,ORACLE总是隐含的发出一些recursive SQL语句,来修改数据字典信息,以便用户可以成功的执行该DDL语句。当需要的数据字典信息没有在共享内存中时,经常会发生Recursive calls,这些Recursive calls会将数据字典信息从硬盘读入内存中。用户不比关心这些recursive SQL语句的执行情况,在需要的时候,ORACLE会自动的在内部执行这些语句。当然DML语句与SELECT都可能引起recursive sql.简单的说,我们可以将触发器视为recursive sql.

    Row Source(行源):用在查询中,由上一操作返回的符合条件的行的集合,即可以是表的全部行数据的集合;也可以是表的部分行数据的集合;也可以为对上2个row source进行连接操作(如join连接)后得到的行数据集合。

    Predicate(谓词):一个查询中的WHERE限制条件

    Driving table(驱动表):该表又称为外层表(OUTER table)。 这个概念用于嵌套与HASH连接中。如果该row source返回较多的行数据,则对所有的后续操作有负面影响。注意此处虽然翻译为驱动表,但实际上翻译为驱动行源(driving row source)更为确切。一般说来,是应用查询的限制条件后,返回较少行源的表作为驱动表,所以如果一个大表在WHERE条件有有限制条件(如等值限 制),则该大表作为驱动表也是合适的,所以并不是只有较小的表可以作为驱动表,正确说法应该为应用查询的限制条件后,返回较少行源的表作为驱动表。在执行 计划中,应该为靠上的那个row source,后面会给出具体说明。在我们后面的描述中,一般将该表称为连接操作的row source 1.

    Probed table(被探查表):该表又称为内层表(INNER table)。在我们从驱动表中得到具体一行的数据后,在该表中寻找符合连接条件的行。所以该表应当为大表(实际上应该为返回较大row source的表)且相应的列上应该有索引。在我们后面的描述中,一般将该表称为连接操作的row source 2.

    组合索引(concatenated index):由多个列构成的索引,如create index idx_emp on emp(col1, col2, col3, ……),则我们称idx_emp索引为组合索引。在组合索引中有一个重要的概念:引导列(leading column),在上面的例子中,col1列为引导列。当我们进行查询时可以使用“where col1 = ? ”,也可以使用“where col1 = ? and col2 = ?”,这样的限制条件都会使用索引,但是“where col2 = ? ”查询就不会使用该索引。所以限制条件中包含先导列时,该限制条件才会使用该组合索引。

    可选择性(selectivity):比较一下列中唯一键的数量和表中的行数,就可以判断该列的可选择性。 如果该列的“唯一键的数量/表中的行数”的比值越接近1,则该列的可选择性越高,该列就越适合创建索引,同样索引的可选择性也越高。在可选择性高的列上进 行查询时,返回的数据就较少,比较适合使用索引查询。

欢迎进入Oracle社区论坛,与200万技术人员互动交流 >>进入
二.oracle访问数据的存取方法

    1) 全表扫描(Full table Scans, FTS)

    为实现全表扫描,oracle读 取表中所有的行,并检查每一行是否满足语句的WHERE限制条件一个多块读 操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定),而不是只读取一个数据块,这极大的减 少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描,而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模 式下,每个数据块只被读一次。

    使用FTS的前提条件:在较大的表上不建议使用全表扫描,除非取出数据的比较多,超过总量的5% —— 10%,或你想使用并行查询功能时。

    使用全表扫描的例子:

    ~~~~~~~~~~~~~~~~~~~~~~~~ sql> explain plan for select * from dual;

    Query Plan

    -----------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=

    table ACCESS FULL DUAL

    2) 通过ROWID的表存取(Table Access by ROWID或rowid lookup)

    行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID来存取数据可以快速定位到目标数据上,是Oracle存取单行数据的最快方法。

    这种存取方法不会用到多块读操作,一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法,如通过索引查询数据。

    使用ROWID存取的方法: sql> explain plan for select * from dept where rowid = ''AAAAyGAADAAAAATAAF'';

    Query Plan

    ------------------------------------

    SELECT STATEMENT [CHOOSE] Cost=1

    table ACCESS BY ROWID DEPT [ANALYZED]


    3)索引扫描(Index Scan或index lookup)

    我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这 种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块。

    在索引中,除了存储每个索引的值外,索引还存储具有此值 的行对应的ROWID值。索引扫描可以由2步组成:(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O,但是对于索引,由于经常使用,绝大多数都已经CACHE到内存中,所以第1步的 I/O经常是逻辑I/O,即数据可以从内存中得到。但是对于第2步来说,如果表比较大,则其数据不可能全在内存中,所以其I/O很有可能是物理I/O,这 是一个机械操作,相对逻辑I/O来说,是极其费时间的。所以如果多大表进行索引扫描,取出的数据如果大于总量的5% —— 10%,使用索引扫描会效率下降很多。如下列所示:SQL> explain plan for select empno, ename from emp where empno=10;

    Query Plan

    ------------------------------------

    SELECT STATEMENT [CHOOSE] Cost=1

    table ACCESS BY ROWID EMP [ANALYZED]

    INDEX UNIQUE SCAN EMP_I1


    但是如果查询的数据能全在索引中找到,就可以避免进行第2步操作,避免了不必要的I/O,此时即使通过索引扫描取出的数据比较多,效率还是很高的

    sql> explain plan for select empno from emp where empno=10;-- 只查询empno列值

    Query Plan

    ------------------------------------

    SELECT STATEMENT [CHOOSE] Cost=1

    INDEX UNIQUE SCAN EMP_I1

    进一步讲,如果sql语句中对索引列进行排序,因为索引已经预先排序好了,所以在执行计划中不需要再对索引列进行排序
    sql> explain plan for select empno, ename from emp

    where empno > 7876 order by empno;

    Query Plan

    --------------------------------------------------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=1

    table ACCESS BY ROWID EMP [ANALYZED]

    INDEX RANGE SCAN EMP_I1 [ANALYZED]


    从这个例子中可以看到:因为索引是已经排序了的,所以将按照索引的顺序查询出符合条件的行,因此避免了进一步排序操作。

根据索引的类型与where限制条件的不同,有4种类型的索引扫描:

    索引唯一扫描(index unique scan)

    索引范围扫描(index range scan)

    索引全扫描(index full scan)

    索引快速扫描(index fast full scan)

    (1) 索引唯一扫描(index unique scan)

    通过唯一索引查找一个数值经常返回单个ROWID.如果存在UNIQUE 或PRIMARY KEY 约束(它保证了语句只存取单行)的话,Oracle经常实现唯一性扫描。

    使用唯一性约束的例子:

    sql> explain plan for

    select empno,ename from emp where empno=10;

    Query Plan

------------------------------------

    SELECT STATEMENT [CHOOSE] Cost=1

    table ACCESS BY ROWID EMP [ANALYZED]

    INDEX UNIQUE SCAN EMP_I1

    (2) 索引范围扫描(index range scan)

    使用一个索引存取多行数据,在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如>、<、<>、>=、<=、between)

    使用索引范围扫描的例子:

    sql> explain plan for select empno,ename from emp

    where empno > 7876 order by empno;

    Query Plan

--------------------------------------------------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=1

    table ACCESS BY ROWID EMP [ANALYZED]

    INDEX RANGE SCAN EMP_I1 [ANALYZED]

    在非唯一索引上,谓词col = 5可能返回多行数据,所以在非唯一索引上都使用索引范围扫描。

    使用index rang scan的3种情况:

    (a) 在唯一索引列上使用了range操作符(> < <> >= <= between)

    (b) 在组合索引上,只使用部分列进行查询,导致查询出多行

    (c) 对非唯一索引列上进行的任何查询。

    (3) 索引全扫描(index full scan)

    与全表扫描对应,也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。

    全索引扫描的例子:

    An Index full scan will not perform single block i/o''s and so it may prove to be inefficient.

    e.g.

    Index BE_IX is a concatenated index on big_emp (empno, ename)

    sql> explain plan for select empno, ename from big_emp order by empno,ename;

    Query Plan

--------------------------------------------------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=26

    INDEX FULL SCAN BE_IX [ANALYZED]

    (4) 索引快速扫描(index fast full scan)

    扫描索引中的所有的数据块,与 index full scan很类似,但是一个显著的区别就是它不对查询出的数据进行排序,即数据不是以排序顺序被返回。在这种存取方法中,可以使用多块读功能,也可以使用并行读入,以便获得最大吞吐量与缩短执行时间。

    索引快速扫描的例子:

    BE_IX索引是一个多列索引: big_emp (empno,ename)

    sql> explain plan for select empno,ename from big_emp;

    Query Plan

------------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=1

    INDEX FAST FULL SCAN BE_IX [ANALYZED]

    只选择多列索引的第2列:

    sql> explain plan for select ename from big_emp;

    Query Plan

------------------------------------------

    SELECT STATEMENT[CHOOSE] Cost=1

    INDEX FAST FULL SCAN BE_IX [ANALYZED]

   三、表之间的连接

    Join是一种试图将两个表结合在一起的谓词,一次只能连接2个表,表连接也可以被称为表关联。在后面的叙 述中,我们将会使用“row source”来代替“表”,因为使用row source更严谨一些,并且将参与连接的2个row source分别称为row source1和row source 2.Join过程的各个步骤经常是串行操作,即使相关的row source可以被并行访问,即可以并行的读取做join连接的两个row source的数据,但是在将表中符合限制条件的数据读入到内存形成row source后,join的其它步骤一般是串行的。有多种方法可以将2个表连接起来,当然每种方法都有自己的优缺点,每种连接类型只有在特定的条件下才会 发挥出其最大优势。

    row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表,即将该表作为驱动表,这样可以先应用某些限制条件,从而得到一个 较小的row source,使连接的效率较高,这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时,应用where子句中对该表的限制条件。

    根据2个row source的连接条件的中操作符的不同,可以将连接分为等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 > B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。上面的各个连接的连接原理都基本一样,所以为了简单期间,下面以等值连接为例进行介绍。

    在后面的介绍中,都已:

    SELECT A.COL1, B.COL2

    FROM A, B

    WHERE A.COL3 = B.COL4;

    为例进行说明,假设A表为Row Soruce1,则其对应的连接操作关联列为COL 3;B表为Row Soruce2,则其对应的连接操作关联列为COL 4;

    连接类型:

    目前为止,无论连接操作符如何,典型的连接类型共有3种:

    排序 - - 合并连接(Sort Merge Join (SMJ) )

    嵌套循环(Nested Loops (NL) )

    哈希连接(Hash Join)

    排序 - - 合并连接(Sort Merge Join, SMJ)

    内部连接过程:

    1) 首先生成row source1需要的数据,然后对这些数据按照连接操作关联列(如A.col3)进行排序。

    2) 随后生成row source2需要的数据,然后对这些数据按照与sort source1对应的连接操作关联列(如B.col4)进行排序。

    3) 最后两边已排序的行被放在一起执行合并操作,即将2个row source按照连接条件连接起来

    下面是连接步骤的图形表示:

    MERGE

    /"

    SORTSORT

    ||

    Row Source 1Row Source 2

    如果row source已经在连接关联列上被排序,则该连接操作就不需要再进行sort操作,这样可以大大提高这种连接操作的连接速度,因为排序是个极其费资源的操 作,特别是对于较大的表。预先排序的row source包括已经被索引的列(如a.col3或b.col4上有索引)或row source已经在前面的步骤中被排序了。尽管合并两个row source的过程是串行的,但是可以并行访问这两个row source(如并行读入数据,并行排序)。

    SMJ连接的例子:SQL> explain plan for

    select /*+ ordered */ e.deptno, d.deptno

    from emp e, dept d

    where e.deptno = d.deptno

    order by e.deptno, d.deptno;

    Query Plan

-------------------------------------

    SELECT STATEMENT [CHOOSE] Cost=17

    MERGE JOIN

    SORT JOIN

    table ACCESS FULL EMP [ANALYZED]

    SORT JOIN

    table ACCESS FULL DEPT [ANALYZED]


    排序是一个费时、费资源的操作,特别对于大表。基于这个原因,SMJ经常不是一个特别有效的连接方法,但是如果2个row source都已经预先排序,则这种连接方法的效率也是蛮高的。

    嵌套循环(Nested Loops, NL)

    这个连接方法有驱动表(外部表)的概念。其实,该连接过程就是一个2层嵌套循环,所以外层循环的次数越少越好,这也就是我们为什么将小表或返回较小 row source的表作为驱动表(用于外层循环)的理论依据。但是这个理论只是一般指导原则,因为遵循这个理论并不能总保证使语句产生的I/O次数最少。有时 不遵守这个理论依据,反而会获得更好的效率。如果使用这种方法,决定使用哪个表作为驱动表很重要。有时如果驱动表选择不正确,将会导致语句的性能很差、很 差。

    内部连接过程:

    Row source1的Row 1 —— Probe ->Row source 2

    Row source1的Row 2 —— Probe ->Row source 2

    Row source1的Row 3 —— Probe ->Row source 2

    ……。

    Row source1的Row n —— Probe ->Row source 2

    从内部连接过程来看,需要用row source1中的每一行,去匹配row source2中的所有行,所以此时保持row source1尽可能的小与高效的访问row source2(一般通过索引实现)是影响这个连接效率的关键问题。这只是理论指导原则,目的是使整个连接操作产生最少的物理I/O次数,而且如果遵守这 个原则,一般也会使总的物理I/O数最少。但是如果不遵从这个指导原则,反而能用更少的物理I/O实现连接操作,那尽管违反指导原则吧!因为最少的物理 I/O次数才是我们应该遵从的真正的指导原则,在后面的具体案例分析中就给出这样的例子。

    在上面的连接过程中,我们称Row source1为驱动表或外部表。Row Source2被称为被探查表或内部表。

    在NESTED LOOPS连接中,Oracle读取row source1中的每一行,然后在row sourc2中检查是否有匹配的行,所有被匹配的行都被放到结果集中,然后处理row source1中的下一行。这个过程一直继续,直到row source1中的所有行都被处理。这是从连接操作中可以得到第一个匹配行的最快的方法之一,这种类型的连接可以用在需要快速响应的语句中,以响应速度为 主要目标。

    如果driving row source(外部表)比较小,并且在inner row source(内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。

    如果不使用并行操作,最好的驱动表是那些应用了where 限制条件后,可以返回较少行数据的的表,所以大表也可能称为驱动表,关键看限制条件。对于并行查询,我们经常选择大表作为驱动表,因为大表可以充分利用并 行功能。当然,有时对查询使用并行操作并不一定会比查询不使用并行操作效率高,因为最后可能每个表只有很少的行符合限制条件,而且还要看你的硬件配置是否 可以支持并行(如是否有多个CPU,多个硬盘控制器),所以要具体问题具体对待。

    NL连接的例子:

    sql> explain plan for

    select a.dname,b.sql

    from dept a,emp b

    where a.deptno = b.deptno;

    Query Plan

-------------------------

    SELECT STATEMENT [CHOOSE] Cost=5

    NESTED LOOPS

    table ACCESS FULL DEPT [ANALYZED]

    table ACCESS FULL EMP [ANALYZED]


    哈希连接(Hash Join, HJ)

    这种连接是在oracle 7.3以后引入的,从理论上来说比NL与SMJ更高效,而且只用在CBO优化器中。

    较小的row source被用来构建hash table与bitmap,第2个row source被用来被hansed,并与第一个row source生成的hash table进行匹配,以便进行进一步的连接。Bitmap被用来作为一种比较快的查找方法,来检查在hash table中是否有匹配的行。特别的,当hash table比较大而不能全部容纳在内存中时,这种查找方法更为有用。这种连接方法也有NL连接中所谓的驱动表的概念,被构建为hash table与bitmap的表为驱动表,当被构建的hash table与bitmap能被容纳在内存中时,这种连接方式的效率极高。

    HASH连接的例子:

    sql> explain plan for

    select /*+ use_hash(emp) */ empno

    from emp, dept

    where emp.deptno = dept.deptno;

    Query Plan

----------------------------

    SELECT STATEMENT[CHOOSE] Cost=3

    HASH JOIN

    table ACCESS FULL DEPT

    table ACCESS FULL EMP


    要使哈希连接有效,需要设置HASH_JOIN_ENABLED=TRUE,缺省情况下该参数为TRUE,另外,不要忘了还要设置 hash_area_size参数,以使哈希连接高效运行,因为哈希连接会在该参数指定大小的内存中运行,过小的参数会使哈希连接的性能比其他连接方式还 要低。

    总结一下,在哪种情况下用哪种连接方法比较好:

    排序 - - 合并连接(Sort Merge Join, SMJ):

    a) 对于非等值连接,这种连接方式的效率是比较高的。

    b) 如果在关联的列上都有索引,效果更好。

    c) 对于将2个较大的row source做连接,该连接方法比NL连接要好一些。

    d) 但是如果sort merge返回的row source过大,则又会导致使用过多的rowid在表中查询数据时,数据库性能下降,因为过多的I/O.

    嵌套循环(Nested Loops, NL):

    a) 如果driving row source(外部表)比较小,并且在inner row source(内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。

    b) NESTED LOOPS有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。

    哈希连接(Hash Join, HJ):

    a) 这种方法是在oracle7后来引入的,使用了比较先进的连接理论,一般来说,其效率应该好于其它2种连接,但是这种连接只能用在CBO优化器中,而且需要设置合适的hash_area_size参数,才能取得较好的性能。

    b) 在2个较大的row source之间连接时会取得相对较好的效率,在一个row source较小时则能取得更好的效率。

    c) 只能用于等值连接中

    笛卡儿乘积(Cartesian Product)

    当两个row source做连接,但是它们之间没有关联条件时,就会在两个row source中做笛卡儿乘积,这通常由编写代码疏漏造成(即程序员忘了写关联条件)。笛卡尔乘积是一个表的每一行依次与另一个表中的所有行匹配。在特殊情 况下我们可以使用笛卡儿乘积,如在星形连接中,除此之外,我们要尽量使用笛卡儿乘积,否则,自己想结果是什么吧!

    注意在下面的语句中,在2个表之间没有连接。

    sql> explain plan for

    select emp.deptno,dept,deptno

    from emp,dept

    Query Plan

------------------------

    SLECT STATEMENT [CHOOSE] Cost=5

    MERGE JOIN CARTESIAN

    table ACCESS FULL DEPT

    SORT JOIN

    table ACCESS FULL EMP

    CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行,dept表有m行,笛卡尔乘积的结果就是得到n * m行结果。

posted @ 2008-08-22 22:33 丑男 阅读(2485) | 评论 (0)编辑 收藏

Fedora 7 安装 nvidia显卡驱动

第一步,到nvidia官方下载驱动,根据自己显卡的型号选择,一定要看readme
第二步,驱动只能在命令行方式下安装,所以要修改/etc/inittab文件
    id:3:initdefault
                3代表文本方式,5代表图形方式
    修改后重启系统
第三步,执行驱动,不出意外会非常的顺利,之后shutdown -r now就完成了

本人也是第一次安装,有不对的地方请大家指正,祝好运

posted @ 2007-07-29 13:48 丑男 阅读(763) | 评论 (0)编辑 收藏

apache rewrite 简单应用

主要需求,DNSwww.mydomain.com指向www.mydomain.com/app/login.do

目前是DNS指向某一个IP,不能将IP对应到10.11.xxx.xxx/app/login.do

生产环境WEB服务器是apache server


解决办法
利用apache rewriter功能,在httpd.conf中找到

#LoadModule rewrite_module modules/mod_rewrite.so

将#号去掉,也就是把mod_rewrite.so模块加载进来

之后在文件结尾处添加

rewriteengine on
rewriterule ^/$ http://10.11.xxx.xxx/app/login.do [R]

posted @ 2007-07-16 21:47 丑男 阅读(294) | 评论 (0)编辑 收藏

[转贴]jasperreport可以用Collection做为数据源



jasperreport可以用Collection做为数据源,这种方式比用Connection方式更为灵活方便
 

posted @ 2005-12-11 18:12 丑男 阅读(398) | 评论 (0)编辑 收藏

我的eclipse插件

1.MyEclipse
   新出的GA4.0,功能非常强大,是我的首先。
   http://www.myeclipseide.com
2.Log4E
   配合和Log4j日志功能
   http://log4e.jayefem.de/update
3.i18n
   编辑国际化资源文件,省得写native2ascii了
   http://propedit.sourceforge.jp/eclipse_plugins/
4.FreeMen
    随时知道内存使用情况
    http://www.junginger.biz/eclipse/

posted @ 2005-09-04 16:13 丑男 阅读(386) | 评论 (0)编辑 收藏

[转帖]学习Reflection

Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。
Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
 
1. 一个简单的例子
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
   public static void main(String args[]) {
       try {
           Class c = Class.forName(args[0]);
           Method m[] = c.getDeclaredMethods();
           for (int i = 0; i < m.length; i++)
               System.out.println(m[i].toString());
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
按如下语句执行:
java DumpMethods java.util.Stack
它的结果输出为:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
2.开始使用 Reflection
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName("java.lang.String");
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它将以文本方式打印出 String 中定义的第一个方法的原型。
在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。
模拟 instanceof 操作符
得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:
class A {
}
public class instance1 {
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("A");
           boolean b1 = cls.isInstance(new Integer(37));
           System.out.println(b1);
           boolean b2 = cls.isInstance(new A());
           System.out.println(b2);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
在这个例子中创建了一个 A 类的 Class 对象,然后检查一些对象是否是 A 的实例。Integer(37) 不是,但 new A() 是。
3.找出类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:
import java.lang.reflect.*;
public class method1 {
   private int f1(Object p, int x) throws NullPointerException {
       if (p == null)
           throw new NullPointerException();
       return x;
   }
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("method1");
           Method methlist[] = cls.getDeclaredMethods();
           for (int i = 0; i < methlist.length; i++) {
               Method m = methlist[i];
               System.out.println("name = " + m.getName());
               System.out.println("decl class = " + m.getDeclaringClass());
               Class pvec[] = m.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                   System.out.println("param #" + j + " " + pvec[j]);
               Class evec[] = m.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                   System.out.println("exc #" + j + " " + evec[j]);
               System.out.println("return type = " + m.getReturnType());
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。
取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。
输出的结果如下:
name = f1
decl class = class method1
param #0 class java.lang.Object
param #1 int
exc #0 class java.lang.NullPointerException
return type = int
-----
name = main
decl class = class method1
param #0 class [Ljava.lang.String;
return type = void
-----

4.获取构造器信息
获取类构造器的用法与上述获取方法的用法类似,如:
import java.lang.reflect.*;
public class constructor1 {
   public constructor1() {
   }
   protected constructor1(int i, double d) {
   }
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("constructor1");
           Constructor ctorlist[] = cls.getDeclaredConstructors();
           for (int i = 0; i < ctorlist.length; i++) {
               Constructor ct = ctorlist[i];
               System.out.println("name = " + ct.getName());
               System.out.println("decl class = " + ct.getDeclaringClass());
               Class pvec[] = ct.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                   System.out.println("param #" + j + " " + pvec[j]);
               Class evec[] = ct.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                   System.out.println("exc #" + j + " " + evec[j]);
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。
这个程序运行的结果是:
name = constructor1
decl class = class constructor1
-----
name = constructor1
decl class = class constructor1
param #0 int
param #1 double
-----
5.获取类的字段(域)
找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:

import java.lang.reflect.*;
public class field1 {
   private double d;
   public static final int i = 37;
   String s = "testing";
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("field1");
           Field fieldlist[] = cls.getDeclaredFields();
           for (int i = 0; i < fieldlist.length; i++) {
               Field fld = fieldlist[i];
               System.out.println("name = " + fld.getName());
               System.out.println("decl class = " + fld.getDeclaringClass());
               System.out.println("type = " + fld.getType());
               int mod = fld.getModifiers();
               System.out.println("modifiers = " + Modifier.toString(mod));
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是:
name = d
decl class = class field1
type = double
modifiers = private
-----
name = i
decl class = class field1
type = int
modifiers = public static final
-----
name = s
decl class = class field1
type = class java.lang.String
modifiers =
-----
和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。

6.根据方法的名称来执行方法
文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:
import java.lang.reflect.*;
public class method2 {
   public int add(int a, int b) {
       return a + b;
   }
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("method2");
           Class partypes[] = new Class[2];
           partypes[0] = Integer.TYPE;
           partypes[1] = Integer.TYPE;
           Method meth = cls.getMethod("add", partypes);
           method2 methobj = new method2();
           Object arglist[] = new Object[2];
           arglist[0] = new Integer(37);
           arglist[1] = new Integer(47);
           Object retobj = meth.invoke(methobj, arglist);
           Integer retval = (Integer) retobj;
           System.out.println(retval.intvalue());
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。
上例中,getMethod 用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的 Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。
7.创建新的对象
对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:
import java.lang.reflect.*;
public class constructor2 {
   public constructor2() {
   }
   public constructor2(int a, int b) {
       System.out.println("a = " + a + " b = " + b);
   }
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
           partypes[0] = Integer.TYPE;
           partypes[1] = Integer.TYPE;
           Constructor ct = cls.getConstructor(partypes);
           Object arglist[] = new Object[2];
           arglist[0] = new Integer(37);
           arglist[1] = new Integer(47);
           Object retobj = ct.newInstance(arglist);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。
8.改变字段(域)的值
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
import java.lang.reflect.*;
public class field2 {
   public double d;
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("field2");
           Field fld = cls.getField("d");
           field2 f2obj = new field2();
           System.out.println("d = " + f2obj.d);
           fld.setDouble(f2obj, 12.34);
           System.out.println("d = " + f2obj.d);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
这个例子中,字段 d 的值被变为了 12.34。
9.使用数组
本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:
import java.lang.reflect.*;
public class array1 {
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("java.lang.String");
           Object arr = Array.newInstance(cls, 10);
           Array.set(arr, 5, "this is a test");
           String s = (String) Array.get(arr, 5);
           System.out.println(s);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}
例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。
下面这段代码提供了一个更复杂的例子:
import java.lang.reflect.*;
public class array2 {
   public static void main(String args[]) {
       int dims[] = new int[]{5, 10, 15};
       Object arr = Array.newInstance(Integer.TYPE, dims);
       Object arrobj = Array.get(arr, 3);
       Class cls = arrobj.getClass().getComponentType();
       System.out.println(cls);
       arrobj = Array.get(arrobj, 5);
       Array.setInt(arrobj, 10, 37);
       int arrcast[][][] = (int[][][]) arr;
       System.out.println(arrcast[3][5][10]);
   }
}
例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。
注意创建数组时的类型是动态的,在编译时并不知道其类型。

posted @ 2005-08-07 01:02 丑男 阅读(397) | 评论 (0)编辑 收藏

[转帖]Eclipse快捷键

作用域
功能
快捷键
全局
查找并替换
Ctrl+F
文本编辑器
查找上一个
Ctrl+Shift+K
文本编辑器
查找下一个
Ctrl+K
全局
撤销
Ctrl+Z
全局
复制
Ctrl+C
全局
恢复上一个选择
Alt+Shift+↓
全局
剪切
Ctrl+X
全局
快速修正
Ctrl1+1
全局
内容辅助
Alt+/
全局
全部选中
Ctrl+A
全局
删除
Delete
全局
上下文信息
Alt+?
Alt+Shift+?
Ctrl+Shift+Space
Java编辑器
显示工具提示描述
F2
Java编辑器
选择封装元素
Alt+Shift+↑
Java编辑器
选择上一个元素
Alt+Shift+←
Java编辑器
选择下一个元素
Alt+Shift+→
文本编辑器
增量查找
Ctrl+J
文本编辑器
增量逆向查找
Ctrl+Shift+J
全局
粘贴
Ctrl+V
全局
重做
Ctrl+Y
 
查看
作用域
功能
快捷键
全局
放大
Ctrl+=
全局
缩小
Ctrl+-
 
窗口
作用域
功能
快捷键
全局
激活编辑器
F12
全局
切换编辑器
Ctrl+Shift+W
全局
上一个编辑器
Ctrl+Shift+F6
全局
上一个视图
Ctrl+Shift+F7
全局
上一个透视图
Ctrl+Shift+F8
全局
下一个编辑器
Ctrl+F6
全局
下一个视图
Ctrl+F7
全局
下一个透视图
Ctrl+F8
文本编辑器
显示标尺上下文菜单
Ctrl+W
全局
显示视图菜单
Ctrl+F10
全局
显示系统菜单
Alt+-
 
导航
作用域
功能
快捷键
Java编辑器
打开结构
Ctrl+F3
全局
打开类型
Ctrl+Shift+T
全局
打开类型层次结构
F4
全局
打开声明
F3
全局
打开外部javadoc
Shift+F2
全局
打开资源
Ctrl+Shift+R
全局
后退历史记录
Alt+←
全局
前进历史记录
Alt+→
全局
上一个
Ctrl+,
全局
下一个
Ctrl+.
Java编辑器
显示大纲
Ctrl+O
全局
在层次结构中打开类型
Ctrl+Shift+H
全局
转至匹配的括号
Ctrl+Shift+P
全局
转至上一个编辑位置
Ctrl+Q
Java编辑器
转至上一个成员
Ctrl+Shift+↑
Java编辑器
转至下一个成员
Ctrl+Shift+↓
文本编辑器
转至行
Ctrl+L
 
搜索
作用域
功能
快捷键
全局
出现在文件中
Ctrl+Shift+U
全局
打开搜索对话框
Ctrl+H
全局
工作区中的声明
Ctrl+G
全局
工作区中的引用
Ctrl+Shift+G
 
文本编辑
作用域
功能
快捷键
文本编辑器
改写切换
Insert
文本编辑器
上滚行
Ctrl+↑
文本编辑器
下滚行
Ctrl+↓
 
文件
作用域
功能
快捷键
全局
保存
Ctrl+X
Ctrl+S
全局
打印
Ctrl+P
全局
关闭
Ctrl+F4
全局
全部保存
Ctrl+Shift+S
全局
全部关闭
Ctrl+Shift+F4
全局
属性
Alt+Enter
全局
新建
Ctrl+N
 
项目
作用域
功能
快捷键
全局
全部构建
Ctrl+B
 
源代码
作用域
功能
快捷键
Java编辑器
格式化
Ctrl+Shift+F
Java编辑器
取消注释
Ctrl+
Java编辑器
注释
Ctrl+/
Java编辑器
添加导入
Ctrl+Shift+M
Java编辑器
组织导入
Ctrl+Shift+O
Java编辑器
使用try/catch块来包围
未设置,太常用了,所以在这里列出,建议自己设置。
也可以使用Ctrl+1自动修正。
 
运行
作用域
功能
快捷键
全局
单步返回
F7
全局
单步跳过
F6
全局
单步跳入
F5
全局
单步跳入选择
Ctrl+F5
全局
调试上次启动
F11
全局
继续
F8
全局
使用过滤器单步执行
Shift+F5
全局
添加/去除断点
Ctrl+Shift+B
全局
显示
Ctrl+D
全局
运行上次启动
Ctrl+F11
全局
运行至行
Ctrl+R
全局
执行
Ctrl+U
 
重构
作用域
功能
快捷键
全局
撤销重构
Alt+Shift+Z
全局
抽取方法
Alt+Shift+M
全局
抽取局部变量
Alt+Shift+L
全局
内联
Alt+Shift+I
全局
移动
Alt+Shift+V
全局
重命名
Alt+Shift+R
全局
重做
Alt+Shift+Y

posted @ 2005-08-06 00:02 丑男 阅读(427) | 评论 (0)编辑 收藏

简单应用日期类

1.自定义格式
   用到java.text.SimpleDateFormat,其中参数如下:
   ss:秒
   mm:分
   hh:小时
   EEEE:星期
   MMMM:月份
   dd:日期
   yyyy:年份
        Date d = new Date();
        SimpleDateFormat sdf 
= new SimpleDateFormat("ss-mm-hh-EEEE-MMMM-dd-yyyy");
        System.
out.println(sdf.format(d));

运行结果
58-21-11-星期五-七月-22-2005

2.DateFormat自带格式
        Date date = new Date(); 

        DateFormat shortDateFormat 
= DateFormat.getDateTimeInstance( DateFormat.SHORT, 
                                                                                                                 DateFormat.SHORT); 
           System.out.println(shortDateFormat.format(date));
           //输出结果      05-7-22 下午11:47


           DateFormat mediumDateFormat = DateFormat.getDateTimeInstance( DateFormat.MEDIUM,
                                                                                                                      DateFormat.MEDIUM); 
           System.out.println (mediumDateFormat.format(date));
           //输出结果       2005-7-22 23:48:11


           DateFormat longDateFormat = DateFormat.getDateTimeInstance( DateFormat.LONG, 
                                                                                                                DateFormat.LONG);
           System.out.println(longDateFormat.format(date));
           //输出结果      2005年7月22日 下午11时48分45秒


           DateFormat fullDateFormat = DateFormat.getDateTimeInstance( DateFormat.FULL,
                                                                                                               DateFormat.FULL);
           System.out.println (fullDateFormat.format(date));
           //输出结果      Saturday, September 29, 2001 8:44:45 PM EDT

posted @ 2005-08-05 23:31 丑男 阅读(414) | 评论 (0)编辑 收藏

[转帖]Log4j比较全面的配置

LOG4J的配置之简单使它遍及于越来越多的应用中了:Log4J配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。择其一二使用就够用了,

 

log4j.rootLogger=DEBUG,CONSOLE,A1,im
log4j.addivity.org.apache=true

 

# 应用于控制台

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n


#应用于文件

log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis

 

# 应用于文件回滚

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


#应用于socket
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n


# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

 

# 发送日志给邮件

log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=xxx@www.xxx.com
log4j.appender.MAIL.SMTPHost=www.wusetu.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=xxx@www.xxx.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

 

# 用于数据库
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout


输出到2000NT日志
 把Log4j压缩包里的NTEventLogAppender.dll拷到WINNT\SYSTEM32目录下

 log4j.logger.NTlog=FATAL, A8
 # APPENDER A8
 log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
 log4j.appender.A8.Source=JavaTest
 log4j.appender.A8.layout=org.apache.log4j.PatternLayout
 log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n

#自定义Appender

log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender

log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = xxx@xxx.net

log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

posted @ 2005-07-24 22:25 丑男 阅读(639) | 评论 (0)编辑 收藏

学习Log4j笔记

今天花了一天的时间来配置Log4j,没想到要那么多时间,还问了不少人,帖子也发了不少,不过最终还是搞定了,不过还有些问题,请高手帮我看看,多谢了。

1.首先是配置简单java project
现在来看log4j.propertise
#级别为DEBUG,二个输出端,分别为stdout,R
log4j.logger.helloappLogger=DEBUG, stdout, R

#控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p (%F:%L) - %m%n

#保存到helloappLoggerlog.txt日志中,大小为100KB
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=F:/code/eclipse/workspace/TestLo4j/log/helloappLoggerlog.txt
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy MMM dd HH:mm:ss} %-5p %c - %m%n

java文件中用到日志
package com;
import org.apache.log4j.*;
public class TestLog4j {
    static Logger logger = Logger.getLogger("helloappLogger");
    public static void main(String[] args) {
//      PropertyConfigurator.configure("log4j.properties");
//      如果.properties在当前目录下可以省略,我放在项目根目录下,和com包同目录
        logger.debug("Debug ...");
        logger.info("Info ...");
        logger.warn("Warn ...");
        logger.error("Error ...");
    }
}

2.web project中配置log4j

还是先来看log4j.perproties

#级别为DEBUG,三个输出端,分别为stdout,FILE,R
log4j.logger.hello=DEBUG, stdout, FILE, R

#stdout是在控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p (%F:%L) - %m%n

#保存在rolling_log_file.log日志中,appender是RollingFileAppender
#需要注意的是File=F:/code/...,不要写成\,这就一点害死我了
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=F:/code/eclipse/workspace/TestCvs/WebRoot/WEB-INF/rolling_log_file.log
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy MMM dd HH:mm:ss} %-5p %c - %m%n

#保存在log_file.log日志中,appender是FileAppender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=F:/code/eclipse/workspace/TestCvs/WebRoot/WEB-INF/log_file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy MMM dd HH:mm:ss} %-5p %c - %m%n

之后要把它加入serlet中,和服务器一起启动,方便其他程序使用

public class Log4jServlet extends HttpServlet {
    public void init() throws ServletException {
        ServletContext sct = getServletContext();
        System.out.println("[Log4j]: The Root Path: " + sct.getRealPath("/"));
        System.out.println("[Log4j]: InitServlet init start...");
        PropertyConfigurator.configure(sct.getRealPath("/")
              +getServletConfig().getInitParameter("propfile"));
        System.out.println("[Log4j]: InitServlet init over.");
    }
}

<servlet>
    <description>init log4j of servlet</description>
    <display-name>log4j servlet</display-name>
    <servlet-name>Log4jServlet</servlet-name>
    <servlet-class>com.testCvs.Log4jServlet</servlet-class>
    <init-param>
     <param-name>propfile</param-name>
     <param-value>/WEB-INF/log4j.properties</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

注:log4j.properties放在/WEB-INF下,servlet自动加载这个文件

至此所有配置应该成功了,不过还是有些问题没有解决好,问了几个朋友也没有得到好的答复,但是现在可以在控制台和文件中输出日志,基本功能达到了。还请各位有空给我看看这个错误,欢迎指正。

错误如下:
log4j:WARN No appenders could be found for logger (org.apache.jasper.compiler.JspRuntimeContext).
log4j:WARN Please initialize the log4j system properly.

posted @ 2005-07-24 22:10 丑男 阅读(9621) | 评论 (8)编辑 收藏