用动作去驱动未来

生命在于运动,让自己身体的每一个细胞都动起来吧.

 

2012年10月17日

List分拆为多少个List对象

用递归实现了这么一个需求,一个list对象中存储了大量的数据,所以打算分拆为多个小的list,然后用多线程处理这些list,实现业务需求。直接上代码:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class TestClass {
    private Map<String,ArrayList<String>> map = new HashMap<String,ArrayList<String>>();
    private int k = 0;

    public
 Map<String,ArrayList<String>> newTableList(ArrayList<String> list,int num) {
        List
<String> tempList = new ArrayList<String>();
        
int size = list.size();
        System.out.println(
"========================================");
        List
<String> newList = (List<String>) list.clone();
        
for (int i = 0; i < size; i++) {
            
if(i < num) {
                String str 
= list.get(i);
                tempList.add(str);
            } 
else {
                
break;
            }
        }
        
        
if (list!=null && size!=0) {
            k
++;
            map.put(String.valueOf(k), (ArrayList
<String>) tempList);
            System.out.println(
"Key:"+k+",list size:"+tempList.size());
            System.out.println(
"========================================");
            
for (int i = 0; i < tempList.size(); i++) {
                String tempStr 
= tempList.get(i);
                
boolean isContains = newList.contains(tempStr);
                
if(isContains) {
                    newList.remove(tempStr);
                }
            }
            newTableList((ArrayList
<String>)newList,num);
        }
        
        
return map;
    }

public static void main(String[] args) throws SQLException {
        TestClass ed = new TestClass();
        ArrayList<String> tempList = new ArrayList<String>();
        tempList.add("111");
        tempList.add("222");
        tempList.add("333");
        tempList.add("444");
        tempList.add("555");
        tempList.add("666");
        tempList.add("777");
        tempList.add("888");
        tempList.add("999");
        tempList.add("100");
        tempList.add("aaa");
        tempList.add("bbb");
        tempList.add("ccc");
        tempList.add("ddd");
        
        ed.newTableList(tempList,5);
    }
}

希望这段代码能帮助到些人。

posted @ 2013-01-30 17:40 黑蚂蚁 阅读(1990) | 评论 (0)编辑 收藏

java对指定目录下文件的读写

最近因为项目的国际化的需要,需要对整个项目的100来个插件做国际化,这是一件痛苦的事情,因为纯体力劳动。为了省点工作量,想着能不能写个程序批处理了,减少点工作量,于是就有了下面的代码。

1.读取指定的(.java)文件:
public static String readFile(String path) throws IOException {
        File f = new File(path);
        StringBuffer res = new StringBuffer();
        String filePathStr = f.getPath();
        System.out.println("获取文件的路径:::::::"+filePathStr);
        
        FileInputStream fis = new FileInputStream(f);
        InputStreamReader isr = new InputStreamReader(fis,Charset.forName("GBK")); //以gbk编码打开文本文件
        BufferedReader br = new BufferedReader(isr, 8192 * 8);
        
        String line = null;
        int linenum = 0;
        while((line=br.readLine())!=null) {
            linenum ++;
            res.append(line+"此处可以添加你自己的字符串处理逻辑"+"\r\n");
        }
        br.close();
        
        return res.toString();
    }
2.读取的文件内容信息写到指定的(.java)文件
public static boolean writeFile(String cont, String path) {
        try {
            File dist = new File(path);
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(dist),"GBK"); 
            writer.write(cont);
            writer.flush();
            writer.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
3.查找指定目录下所有符合条件的.java文件,并更新文件信息
    /**
     * 查找文件
     * @param f
     * @throws IOException
     */
    public static void findFile(File f) throws IOException {
        if(f.exists()) {
            if(f.isDirectory()) {
                for(File fs:f.listFiles(ff)) {
                    findFile(fs);
                }
            } else {
                    updateFile(f);
            }
        }
    }
    
    /**
     * 逐行读java文件
     * @param f
     * @throws IOException
     */
    private static void updateFile(File f) throws IOException {
        String filePathStr = f.getPath();
        System.out.println("开始读取文件的路径:::::::"+filePathStr);
        FileInputStream fis = new FileInputStream(f);
        InputStreamReader isr = new InputStreamReader(fis,Charset.forName("GBK")); //以gbk编码打开文本文件
        BufferedReader br = new BufferedReader(isr, 8192 * 8);
        
        String line = null;
        int linenum = 0;
        StringBuffer res = new StringBuffer();
        while((line=br.readLine())!=null) {
            String updateStr= updateStr(line);
            res.append(updateStr+"\r\n");
            
            if(!line.trim().equals(updateStr.trim())) {
                linenum ++;
            }
        }
        br.close();
        
        //如果文件有修改,则修改后的文件,覆盖原有文件
        if(linenum>0) {
            System.out.println("=============================");
            System.out.println("filePathStr:"+filePathStr);
            System.out.println("文件修改了:"+linenum+"处。");
            System.out.println("=============================");
            String cont = res.toString();
            ReadWriteFile.write(cont, filePathStr);
        }
    }
    
    /**
     * 验证读取的字符串信息
     * 和更新字符串信息
     * @param str
     */
    private static String updateStr(String str) {
        //判断字符串是否是需要更新的字符串
        boolean isok = filterStr(str);
        int strNum = StringValidation.strNum(str, StringValidation.ch);
        if(isok || strNum == 0) {
            return str;
        } else {
            String temp = ""; 
            for(int i=1;i<=strNum/2;i++) {
                temp += " //$NON-NLS-"+i+"$"; //需要添加的字符
            }
            str = str+temp;
        }
        return str;
    }
    
    //过滤文件类型
    private static FileFilter ff = new FileFilter() {
        public boolean accept(File pathname) {
            String path = pathname.getName().toLowerCase();
            logger.info("FileFilter path::::"+path);
            //只匹配 .java 结尾的文件
            if (pathname.isDirectory() || path.endsWith(".java")) {
                return true;
            }
            return false;
        }
    };

    /**
     * 过滤掉不需要处理的字符串
     * @param str
     * @return
     */
    public static boolean filterStr(String str) {
        boolean isok = false;
        
        //过滤字符串
        isok = (str.indexOf("import ")>=0)
                || (str.indexOf("package ")>=0)
                || (str.indexOf(" class ")>=0)
                || (str.indexOf("//$NON-NLS")>=0)
                || (str.indexOf("//")==0)
                || (str.indexOf("/*")>=0)
                || (str.indexOf("*")>=0)
                || (str.trim().indexOf("@")==0)
                || (str.indexOf("\"")==-1)
                || ("".equals(str))
                || isCh(str);
        return isok;
    }

    /**
     * 验证字符串是否含有中文字符
     * @param str
     * @return
     */
    public static boolean isCh(String str) {
        Pattern   pa   =   Pattern.compile("[\u4E00-\u9FA0]");
        Matcher   m   =   pa.matcher(str);
        boolean isok = m.find();
        return isok;
    }

总结:当我们拿到一个别人给的需求,先不要急于去处理,先分析,再分析,然后做出最优的解决方案,处理好这项工作。

posted @ 2012-11-23 15:32 黑蚂蚁| 编辑 收藏

Eclipse下添加反编译插件jad.exe

相信学习java的都会用到反编译工具查看.class文件,接下来简单的记录下,在eclipse下安装反编译插件的过程,希望能帮助到你。

首先: 我们需要下载:net.sf.jadclipse_3.3.0.jar  参考下载地址:http://download.csdn.net/detail/lk_kuaile/1725313
其次: 还需要下载:jad.exe 参考下载地址:http://ishare.iask.sina.com.cn/f/15267016.html?from=like

接下来:我把下载的 net.sf.jadclipse_3.3.0.jar 放入到自己的文件夹下:eclipse\plugins 目录下。
            重启eclipse,打开window-preferences--java 指定jad.exe的绝对路径。
           
点击ok,就可以了。我们就可以很方便的在Eclipse下查看jar下的.class 文件了。

posted @ 2012-11-09 16:46 黑蚂蚁 阅读(2131) | 评论 (3)编辑 收藏

ECLIPSE 添加插件3种方法

eclipse 添加插件有3中方法:

    第一种:解压eclipse 插件 里面分别包含两个文件夹features和plugins ,然后把两个文件夹分别复制到eclipse 下所对应的文件夹下。删除 configuration文件夹下的 org.eclipse.update文件夹。
重新启动eclipse,可以在eclipse的菜单"Help"-->"About Eclipse SDK"-->"Feature Details" 和"Plug-in Details"中看到新安装的插件。

    第二种:新建一个文件夹并命名为eclipse,解压eclipse 插件,分别将文件夹features和文件夹plugins 放入该文件夹下,然后找到eclipse SDK下的links文件夹,在links文件夹中新建一个YourFileName.link文件,内容是"path=${your eclipse-plugin path}" 。重新启动eclipse,可以在eclipse的菜单"Help"-->"About Eclipse SDK"-->"Feature Details" 和"Plug-in Details"中看到新安装的插件。


   第三种:解压eclipse 插件,分别将文件夹features和文件夹plugins 放入eclipse安装文件夹下。


疑问:为什么把插件的文件夹features和文件夹plugins复制到eclipse安装文件夹下,原来文件夹features和文件夹plugins的内容不被覆盖?

posted @ 2012-11-08 18:04 黑蚂蚁 阅读(307) | 评论 (0)编辑 收藏

eclipse3.7插件构建自定义右键菜单

原文地址:http://www.cnblogs.com/skyme/archive/2012/01/12/2320128.html


posted @ 2012-11-08 17:55 黑蚂蚁 阅读(355) | 评论 (0)编辑 收藏

Enum的使用与分析

示例:

 1     public enum EnumTest {  
 2          FRANK("The given name of me"),  
 3          LIU("The family name of me");  
 4          private String context;  
 5          private String getContext(){  
 6          return this.context;  
 7          }  
 8          private EnumTest(String context){  
 9          this.context = context;  
10          }  
11          public static void main(String[] args){  
12          for(EnumTest name :EnumTest.values()){  
13          System.out.println(name+" : "+name.getContext());  
14          }  
15          System.out.println(EnumTest.FRANK.getDeclaringClass());  
16          }  
17      
18     } 

Java中枚举实现的分析:

示例:

public enum Color{    
    RED,BLUE,BLACK,YELLOW,GREEN    
}
  1.  

显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类。 而这些类都是类库中Enum类的子类(java.lang.Enum<E>)。它们继承了这个Enum中的许多有用的方法。我们对代码编译之 后发现,编译器将enum类型单独编译成了一个字节码文件:Color.class。

Color字节码代码:

  1. final enum hr.test.Color {  
  2.     
  3.  // 所有的枚举值都是类静态常量  
  4. &nbsp;public static final enum hr.test.Color RED;  
  5. &nbsp;public static final enum hr.test.Color BLUE;  
  6.  public static final enum hr.test.Color BLACK;  
  7.  public static final enum hr.test.Color YELLOW;  
  8.  public static final enum hr.test.Color GREEN;  
  9.    
  10. private static final synthetic hr.test.Color[] ENUM$VALUES;  
  11.     
  12.   // 初始化过程,对枚举类的所有枚举值对象进行第一次初始化  
  13. &nbsp;static {  
  14.        0  new hr.test.Color [1]   
  15.       3  dup  
  16.       4  ldc <String "RED"> [16] //把枚举值字符串"RED"压入操作数栈  
  17.       6  iconst_0  // 把整型值0压入操作数栈  
  18.       7  invokespecial hr.test.Color(java.lang.String, int) [17] //调用Color类的私有构造器创建Color对象RED  
  19.      10  putstatic hr.test.Color.RED : hr.test.Color [21]  //将枚举对象赋给Color的静态常量RED。  
  20.       .........  枚举对象BLUE等与上同  
  21.     102  return 
  22. };  
  23.     
  24.   // 私有构造器,外部不可能动态创建一个枚举类对象(也就是不可能动态创建一个枚举值)。  
  25.  private Color(java.lang.String arg0, int arg1){  
  26.      // 调用父类Enum的受保护构造器创建一个枚举对象  
  27.      3  invokespecial java.lang.Enum(java.lang.String, int) [38]  
  28. };  
  29. &nbsp;  
  30.  public static hr.test.Color[] values();  
  31.     
  32.    // 实现Enum类的抽象方法    
  33.   public static hr.test.Color valueOf(java.lang.String arg0);  

下面我们就详细介绍enum定义的枚举类的特征及其用法。(后面均用Color举例)

1、Color枚举类就是class,而且是一个不可以被继承的final类。

其枚举值(RED,BLUE...)都是Color类型的类静态常量, 我们可以通过下面的方式来得到Color枚举类的一个实例:

  1. Color c=Color.RED;  

注意:这些枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写。

2、即然枚举类是class,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:

(1) 构造器只是在构造枚举值的时候被调用。

 1     enum Color{  
 2                     RED(255,0,0),BLUE(0,0,255),BLACK(0,0,0),YELLOW(255,255,0),GREEN(0,255,0);  
 3                     //构造枚举值,比如RED(255,0,0)  
 4                     private Color(int rv,int gv,int bv){  
 5                      this.redValue=rv;  
 6                      this.greenValue=gv;  
 7                      this.blueValue=bv;  
 8                     }  
 9      
10                     public String toString(){  //覆盖了父类Enum的toString()  
11                     return super.toString()+"("+redValue+","+greenValue+","+blueValue+")";  
12                     }  
13          
14                     private int redValue;  //自定义数据域,private为了封装。  
15                     private int greenValue;  
16                     private int blueValue;  
17      }

(2) 构造器只能私有private,绝对不允许有public构造器。 这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。

但枚举类的方法和数据域可以允许外部访问。

  1. public static void main(String args[])  
  2. {  
  3.         // Color colors=new Color(100,200,300);  //wrong  
  4.            Color color=Color.RED;  
  5.            System.out.println(color);  // 调用了toString()方法  
  6. }     

3、所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。

(1) ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。

  1. Color.RED.ordinal(); //返回结果:0  
  2. Color.BLUE.ordinal(); //返回结果:1 

(2) compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺 序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)

  1. Color.RED.compareTo(Color.BLUE); //返回结果 -1 

(3) values()方法: 静态方法,返回一个包含全部枚举值的数组。

  1. Color[] colors=Color.values();  for(Color c:colors){  System.out.print(c+","); }  
  2. //返回结果:RED,BLUE,BLACK YELLOW,GREEN,  

(4) toString()方法: 返回枚举常量的名称。

  1. Color c=Color.RED;  
  2. System.out.println(c);//返回结果: RED 

(5) valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。

  1. Color.valueOf("BLUE");   //返回结果: Color.BLUE 

(6) equals()方法: 比较两个枚举类对象的引用。

  1. //JDK源代码:        
  2. public final boolean equals(Object other) {    
  3.         return this==other;    

4、枚举类可以在switch语句中使用。

  1. Color color=Color.RED;  
  2. switch(color){  
  3.         case RED: System.out.println("it's red");break;  
  4.         case BLUE: System.out.println("it's blue");break;  
  5.         case BLACK: System.out.println("it's blue");break;  

原文链接:http://www.cnblogs.com/frankliiu-java/archive/2010/12/07/1898721.html

posted @ 2012-11-07 15:33 黑蚂蚁 阅读(252) | 评论 (0)编辑 收藏

hibernate二级缓存攻略

很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。

hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。

二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true


缓存可以简单的看成一个Map,通过key在缓存里面找value。

Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是 iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
&lt;cache usage="read-write"/&gt;
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
&lt;cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /&gt;
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果 eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put的 元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候 是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次 iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为 iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择 若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是 list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了

查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
&lt;cache name="net.sf.hibernate.cache.StandardQueryCache"
   maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
   timeToLiveSeconds="7200" overflowToDisk="true"/&gt;
&lt;cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
   maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/&gt;
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
&lt;cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" /&gt;
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是"tiger%",那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方 法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的 行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是 一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同 条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和 class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么 list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时 间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意 了。

另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。

当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时 间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这 些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。

Collection缓存
需要在hbm的collection里面设置
&lt;cache usage="read-write"/&gt;
假如class是Cat,collection叫children,那么ehcache里面配置
&lt;cache name="com.xxx.pojo.Cat.children"
   maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
   overflowToDisk="true" /&gt;
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。

缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过

读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。


使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过 hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删 除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
          Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
          Evict an entry from the second-level cache.
void evictCollection(String roleName)
          Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
          Evict an entry from the second-level cache.
void evictQueries()
          Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
          Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用 evictQueries(String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?

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

总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。
如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为 底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

================================================================================
原文出处:http://www.iteye.com/topic/18904,对hibernate 二级缓存 讲解的很彻底,所以转载了,一同分享.

posted @ 2012-11-07 15:09 黑蚂蚁 阅读(243) | 评论 (0)编辑 收藏

(按Ctrl+C)选中的table表单中的数据,粘贴(按Ctrl+V)到目标文件(Excel,Word...)

希望这个方法能帮助到你:
 1 public static void addCopyListener(final Table table) {
 2         table.addKeyListener(new KeyAdapter() {
 3             public void keyPressed(KeyEvent e) {
 4                 if (e.stateMask == SWT.CTRL && e.keyCode == 'c') {
 5                     Clipboard board = new Clipboard(Display.getDefault());
 6                     TableItem[] item = table.getSelection();
 7                     TableColumn[] tc = table.getColumns();
 8 
 9                     String copyStr = "";
10                     for (int i = 0; i < item.length; i++) {
11                         for (int j = 0; j < tc.length; j++) {
12                             copyStr += item[i].getText(j) + "\t";
13                         }
14                         copyStr = copyStr + "\n";
15                     }
16                     if (!"".equals(copyStr)) {
17                         board.setContents(new String[] { copyStr }, new Transfer[] { TextTransfer.getInstance() });
18                     }
19                 }
20             }
21         });
22     }

posted @ 2012-11-07 10:11 黑蚂蚁 阅读(1162) | 评论 (0)编辑 收藏

svn 红色感叹号

在解决插件与插件的关系的时候,一个不小心,点击添加插件的依赖的时候,点到了下面一个插件文件,导致两个插件相互依赖了,就出现了“svn 红色感叹号”标记,去掉相互依赖,此问题解决。

posted @ 2012-10-17 16:04 黑蚂蚁 阅读(933) | 评论 (0)编辑 收藏

导航

统计

公告

路在脚下,此刻,出发。

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

相册

搜索

最新评论

阅读排行榜

评论排行榜