<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    用動作去驅(qū)動未來

    生命在于運動,讓自己身體的每一個細(xì)胞都動起來吧.

     

    置頂隨筆

    [置頂]List分拆為多少個List對象

    用遞歸實現(xiàn)了這么一個需求,一個list對象中存儲了大量的數(shù)據(jù),所以打算分拆為多個小的list,然后用多線程處理這些list,實現(xiàn)業(yè)務(wù)需求。直接上代碼:

    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 黑螞蟻 閱讀(1993) | 評論 (0)編輯 收藏

    [置頂]hibernate二級緩存攻略

    很多人對二級緩存都不太了解,或者是有錯誤的認(rèn)識,我一直想寫一篇文章介紹一下hibernate的二級緩存的,今天終于忍不住了。
    我的經(jīng)驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。

    hibernate的session提供了一級緩存,每個session,對同一個id進(jìn)行兩次load,不會發(fā)送兩條sql給數(shù)據(jù)庫,但是session關(guān)閉的時候,一級緩存就失效了。

    二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設(shè)置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來說,是根據(jù)ID來找的,緩存的key就是ID,value是POJO。無論list,load還是 iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取數(shù)據(jù)庫select id出來,然后一個id一個id的load,如果在緩存里面有,就從緩存取,沒有的話就去數(shù)據(jù)庫load。假設(shè)是讀寫緩存,需要設(shè)置:
    &lt;cache usage="read-write"/&gt;
    如果你使用的二級緩存實現(xiàn)是ehcache的話,需要配置ehcache.xml
    &lt;cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /&gt;
    其中eternal表示緩存是不是永遠(yuǎn)不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如果 eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發(fā)呆時間,是可選的。當(dāng)往緩存里面put的 元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分?jǐn)?shù)據(jù)保存在硬盤上的臨時文件里面。
    每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然后使用defaultCache的配置,這樣多個class會共享一個配置。
    當(dāng)某個ID通過hibernate修改時,hibernate會知道,于是移除緩存。
    這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什么時候 是第一次,而且每次查詢的條件通常是不一樣的,假如數(shù)據(jù)庫里面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次 iterate的時候卻查詢到30至70號id,那么30-50是從緩存里面取的,51到70是從數(shù)據(jù)庫取的,共發(fā)送1+20條sql。所以我一直認(rèn)為 iterate沒有什么用,總是會有1+N的問題。
    (題外話:有說法說大型查詢用list會把整個結(jié)果集裝入內(nèi)存,很慢,而iterate只select id比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結(jié)果集裝進(jìn)來,假如一頁20條的話,iterate共需要執(zhí)行21條語句,list雖然選擇 若干字段,比iterate第一條select id語句慢一些,但只有一條語句,不裝入整個結(jié)果集hibernate還會根據(jù)數(shù)據(jù)庫方言做優(yōu)化,比如使用mysql的limit,整體看來應(yīng)該還是 list快。)
    如果想要對list或者iterate查詢的結(jié)果緩存,就要用到查詢緩存了

    查詢緩存
    首先需要配置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;
    如果省略第二行,不設(shè)置cacheRegion的話,那么會使用上面提到的標(biāo)準(zhǔn)查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

    對于查詢緩存來說,緩存的key是根據(jù)hql生成的sql,再加上參數(shù),分頁等信息(可以通過日志輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。
    比如hql:
    from Cat c where c.name like ?
    生成大致如下的sql:
    select * from cat c where c.name like ?
    參數(shù)是"tiger%",那么查詢緩存的key*大約*是這樣的字符串(我是憑記憶寫的,并不精確,不過看了也該明白了):
    select * from cat c where c.name like ? , parameter:tiger%
    這樣,保證了同樣的查詢、同樣的參數(shù)等條件下具有一樣的key。
    現(xiàn)在說說緩存的value,如果是list方式的話,value在這里并不是整個結(jié)果集,而是查詢出來的這一串ID。也就是說,不管是list方 法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執(zhí)行一條sql,iterate執(zhí)行1+N條,多出來的 行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據(jù)緩存的key去緩存里面查到了value,value是 一串id,然后在到class的緩存里面去一個一個的load出來。這樣做是為了節(jié)約內(nèi)存。
    可以看出來,查詢緩存需要打開相關(guān)類的class緩存。list和iterate方法第一次執(zhí)行的時候,都是既填充查詢緩存又填充class緩存的。
    這里還有一個很容易被忽視的重要問題,即打開查詢緩存以后,即使是list方法也可能遇到1+N的問題!相同 條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數(shù)據(jù),總是發(fā)送一條sql語句到數(shù)據(jù)庫獲取全部數(shù)據(jù),然后填充查詢緩存和 class緩存。但是第二次執(zhí)行的時候,問題就來了,如果你的class緩存的超時時間比較短,現(xiàn)在class緩存都超時了,但是查詢緩存還在,那么 list方法在獲取id串以后,將會一個一個去數(shù)據(jù)庫load!因此,class緩存的超時時間一定不能短于查詢緩存設(shè)置的超時時間!如果還設(shè)置了發(fā)呆時 間的話,保證class緩存的發(fā)呆時間也大于查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意 了。

    另外,如果hql查詢包含select字句,那么查詢緩存里面的value就是整個結(jié)果集了。

    當(dāng)hibernate更新數(shù)據(jù)庫的時候,它怎么知道更新哪些查詢緩存呢?
    hibernate在一個地方維護(hù)每個表的最后更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
    當(dāng)通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時 間和這個緩存所查詢的表,當(dāng)hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這 些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。
    可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

    Collection緩存
    需要在hbm的collection里面設(shè)置
    &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是根據(jù)某個字段排序的,當(dāng)其中一個元素更新了該字段時,導(dǎo)致順序改變時,collection緩存里面的順序沒有做更新。

    緩存策略
    只讀緩存(read-only):沒有什么好說的
    讀/寫緩存(read-write):程序可能要的更新數(shù)據(jù)
    不嚴(yán)格的讀/寫緩存(nonstrict-read-write):需要更新數(shù)據(jù),但是兩個事務(wù)更新同一條記錄的可能性很小,性能比讀寫緩存好
    事務(wù)緩存(transactional):緩存支持事務(wù),發(fā)生異常的時候,緩存也能夠回滾,只支持jta環(huán)境,這個我沒有怎么研究過

    讀寫緩存和不嚴(yán)格讀寫緩存在實現(xiàn)上的區(qū)別在于,讀寫緩存更新緩存的時候會把緩存里面的數(shù)據(jù)換成一個鎖,其他事務(wù)如果去取相應(yīng)的緩存數(shù)據(jù),發(fā)現(xiàn)被鎖住了,然后就直接取數(shù)據(jù)庫查詢。
    在hibernate2.1的ehcache實現(xiàn)中,如果鎖住部分緩存的事務(wù)發(fā)生了異常,那么緩存會一直被鎖住,直到60秒后超時。
    不嚴(yán)格讀寫緩存不鎖定緩存中的數(shù)據(jù)。


    使用二級緩存的前置條件
    你的hibernate程序?qū)?shù)據(jù)庫有獨占的寫訪問權(quán),其他的進(jìn)程更新了數(shù)據(jù)庫,hibernate是不可能知道的。你操作數(shù)據(jù)庫必需直接通過 hibernate,如果你調(diào)用存儲過程,或者自己使用jdbc更新數(shù)據(jù)庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪 除是不更新二級緩存的,但是據(jù)說3.1已經(jīng)解決了這個問題。
    這個限制相當(dāng)?shù)募?,有時候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優(yōu)化,很郁悶吧。
    SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調(diào)用這些方法移除緩存,這些方法是:
    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.
    不過我不建議這樣做,因為這樣很難維護(hù)。比如你現(xiàn)在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用 evictQueries(String cacheRegion)移除了3個查詢緩存,然后用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關(guān)查詢緩存,可能會忘記更新這里的移除代碼。如果你的 jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什么地方也要做相應(yīng)的改動嗎?

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

    總結(jié):
    不要想當(dāng)然的以為緩存一定能提高性能,僅僅在你能夠駕馭它并且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當(dāng)?shù)氖褂眠€可能導(dǎo)致讀出臟數(shù)據(jù)。
    如果受不了hibernate的諸多限制,那么還是自己在應(yīng)用程序的層面上做緩存吧。
    在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數(shù)據(jù)庫還是要實現(xiàn)自己的緩存,盡管數(shù)據(jù)庫有緩存,咱們的應(yīng)用程序還是要做緩存。因為 底層的緩存它并不知道高層要用這些數(shù)據(jù)干什么,只能做的比較通用,而高層可以有針對性的實現(xiàn)緩存,所以在更高的級別上做緩存,效果也要好些吧。

    ================================================================================
    原文出處:http://www.iteye.com/topic/18904,對hibernate 二級緩存 講解的很徹底,所以轉(zhuǎn)載了,一同分享.

    posted @ 2012-11-07 15:09 黑螞蟻 閱讀(248) | 評論 (0)編輯 收藏

    [置頂]java swt table 點擊表頭排序

    public class PickerShellTableSort {
        private Table table;
        private Image upImage;
        private Image downImage;
        
        private int[] sortFlags;
        private int[] sortColIndexes;
        
        public PickerShellTableSort(Table table) {
            int[] sortCols = new int[table.getColumnCount()];
            for (int i = 1; i < sortCols.length; i++) {
                sortCols[i] = i;
            }
            
            this.table = table;
            this.sortColIndexes = sortCols;     //需要排序的索引
            this.sortFlags = new int[table.getColumnCount()];
            
            init();
        }
        
        private void init() {
            for (int i = 0; i < sortColIndexes.length; i++) {
                final int sortColIndex = this.sortColIndexes[i];
                TableColumn col = table.getColumn(sortColIndex);
                
                col.addListener(SWT.Selection, new Listener() {
                    public void handleEvent(Event event) {
                        columnHandleEvent(event, sortColIndex);
                    }
                });
            }
            
            this.upImage = FrameCommonActivator.getImageDescriptor("icons/up.gif").createImage();
            this.downImage = FrameCommonActivator.getImageDescriptor("icons/down.gif").createImage();
        }
        
        private void columnHandleEvent(Event event, int sortColIndex) {
            try {
                for (int i = 0; i < sortColIndexes.length; i++) {
                    TableColumn tabCol = table.getColumn(i);
                    tabCol.setImage(null);
                }
                
                boolean selectColumnType = this.isStringOrNumberType(sortColIndex);
                
                 if (this.sortFlags[sortColIndex] == 1) {
                     clearSortFlags();
                    this.sortFlags[sortColIndex] = -1;
                    
                    if(selectColumnType) {
                        this.addNumberSorter(table.getColumn(sortColIndex), true);
                    } else {
                        this.addStringSorter(table.getColumn(sortColIndex), true);
                    }
                    
                    table.getColumn(sortColIndex).setImage(this.upImage);
                } else {
                    this.sortFlags[sortColIndex] = 1;
                    
                    if(selectColumnType) {
                        this.addNumberSorter(table.getColumn(sortColIndex), false);
                    } else {
                        this.addStringSorter(table.getColumn(sortColIndex), false);
                    }
                    
                    table.getColumn(sortColIndex).setImage(this.downImage);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        /**
         * @param table
         * @param column
         * @param isAscend  
         */
        private void addStringSorter(TableColumn column,boolean isAscend) {
            
              Collator comparator = Collator.getInstance(Locale.getDefault());
              int columnIndex = getColumnIndex(table, column);
              TableItem[] items = table.getItems();
              //使用冒泡法進(jìn)行排序
              for (int i = 1; i < items.length; i++) {
                  String str2value = items[i].getText(columnIndex);
                  if(str2value.equalsIgnoreCase("")){
                     //當(dāng)遇到表格中的空項目時,就停止往下檢索排序項目
                     break;
                  }
                  for (int j = 0; j < i; j++) {
                     String str1value = items[j].getText(columnIndex);
                     boolean isLessThan = comparator.compare(str2value, str1value) < 0;     
                     if ((isAscend && isLessThan) || (!isAscend && !isLessThan)) {
                          String[] values = getTableItemText(table, items[i]);
                          Object obj = items[i].getData();
                          items[i].dispose();
                          TableItem item = new TableItem(table, SWT.NONE, j);
                          item.setText(values);
                          item.setData(obj);
                          items = table.getItems();
                          break;
                     }
                  }
               }
               table.setSortColumn(column);
               table.setSortDirection((isAscend ? SWT.UP : SWT.DOWN));
               isAscend = !isAscend;
          }
        
        
        private void addNumberSorter(TableColumn column,boolean isAscend) {
            
              int columnIndex = getColumnIndex(table, column);
              TableItem[] items = table.getItems();
              //使用冒泡法進(jìn)行排序
              for (int i = 1; i < items.length; i++) {
               String strvalue2 = items[i].getText(columnIndex);
               if(strvalue2.equalsIgnoreCase("")){
                //當(dāng)遇到表格中的空項目時,就停止往下檢索排序項目
                break;
               }
               
               for (int j = 0; j < i; j++) {
                String strvalue1 = items[j].getText(columnIndex);
                
                //將字符串類型數(shù)據(jù)轉(zhuǎn)化為float類型
                float numbervalue1=Float.valueOf(strvalue1);
                float numbervalue2=Float.valueOf(strvalue2);
                
                boolean isLessThan =false;
                if(numbervalue2<numbervalue1){
                    isLessThan =true;
                }    
                
                if ((isAscend && isLessThan) || (!isAscend && !isLessThan)) {
                     String[] values = getTableItemText(table, items[i]);
                     Object obj = items[i].getData();
                     items[i].dispose();
                     TableItem item = new TableItem(table, SWT.NONE, j);
                     item.setText(values);
                     item.setData(obj);
                     items = table.getItems();
                     break;
                }
               }
              }
              
              table.setSortColumn(column);
              table.setSortDirection((isAscend ? SWT.UP : SWT.DOWN));
              isAscend = !isAscend;
         }
        
        private  int getColumnIndex(Table table, TableColumn column) {
            TableColumn[] columns = table.getColumns();
            for (int i = 0; i < columns.length; i++) {
                if (columns[i].equals(column))
                    return i;
            }
            return -1;
         }
        
        private  String[] getTableItemText(Table table, TableItem item) {
            int count = table.getColumnCount();
            String[] strs = new String[count];
            for (int i = 0; i < count; i++) {
                strs[i] = item.getText(i);
            }
            return strs;
         }

         private void clearSortFlags() {
            for (int i = 0; i < table.getColumnCount(); i++) {
                this.sortFlags[i] = 0;
            }
         }
        
         /**
          * 判斷當(dāng)前選中列的數(shù)據(jù)類型
          * @return
          */
         private boolean isStringOrNumberType(int selectColumnIndex) {
             boolean isok = false ;
            
             TableItem[] items = table.getItems();
             String[] str = new String[items.length];
            
             for (int i = 0; i < items.length; i++) {
                 str[i] = items[i].getText(selectColumnIndex);
             }
            
             for (int i = 0; i < str.length; i++) {
                String string = str[i];
                isok = string.matches("^(-|\\+)?\\d+\\.?\\d*$");
                //如果這一列中有一個是字符串,也按字符串排序
                if(!isok) {
                    return isok;
                }
             }
            
             return isok ;
         }
        
    }

    posted @ 2012-04-24 09:56 黑螞蟻 閱讀(2166) | 評論 (0)編輯 收藏

    [置頂]tapestry5中表單提交問題

    org.apache.tapestry5.runtime.ComponentEventException
    Forms require that the request method be POST and that the t:formdata query parameter have values.


    提交表單form就會出現(xiàn)這個問題,
    <t:form >
      <t:submit t:id="login" value="提交" />
    </t:form>

    用火狐沒問題,ie出現(xiàn)的概率就很大,我試著捕獲這個異常,頁面雖不至于馬上報錯,但刷新就會出現(xiàn),會在原來的路徑后加上一個.form也即是form id。

    希望大蝦們幫忙解決,困擾我很久了.

    posted @ 2010-04-23 19:49 黑螞蟻 閱讀(448) | 評論 (0)編輯 收藏

    2013年1月30日

    List分拆為多少個List對象

    用遞歸實現(xiàn)了這么一個需求,一個list對象中存儲了大量的數(shù)據(jù),所以打算分拆為多個小的list,然后用多線程處理這些list,實現(xiàn)業(yè)務(wù)需求。直接上代碼:

    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 黑螞蟻 閱讀(1993) | 評論 (0)編輯 收藏

    2012年11月23日

    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.讀取的文件內(nèi)容信息寫到指定的(.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 結(jié)尾的文件
                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("http://$NON-NLS")>=0)
                    || (str.indexOf("http://")==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;
        }

    總結(jié):當(dāng)我們拿到一個別人給的需求,先不要急于去處理,先分析,再分析,然后做出最優(yōu)的解決方案,處理好這項工作。

    posted @ 2012-11-23 15:32 黑螞蟻| 編輯 收藏

    2012年11月9日

    Eclipse下添加反編譯插件jad.exe

    相信學(xué)習(xí)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 黑螞蟻 閱讀(2138) | 評論 (3)編輯 收藏

    2012年11月8日

    ECLIPSE 添加插件3種方法

    eclipse 添加插件有3中方法:

        第一種:解壓eclipse 插件 里面分別包含兩個文件夾features和plugins ,然后把兩個文件夾分別復(fù)制到eclipse 下所對應(yīng)的文件夾下。刪除 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文件,內(nèi)容是"path=${your eclipse-plugin path}" 。重新啟動eclipse,可以在eclipse的菜單"Help"-->"About Eclipse SDK"-->"Feature Details" 和"Plug-in Details"中看到新安裝的插件。


       第三種:解壓eclipse 插件,分別將文件夾features和文件夾plugins 放入eclipse安裝文件夾下。


    疑問:為什么把插件的文件夾features和文件夾plugins復(fù)制到eclipse安裝文件夾下,原來文件夾features和文件夾plugins的內(nèi)容不被覆蓋?

    posted @ 2012-11-08 18:04 黑螞蟻 閱讀(313) | 評論 (0)編輯 收藏

    eclipse3.7插件構(gòu)建自定義右鍵菜單

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


    posted @ 2012-11-08 17:55 黑螞蟻 閱讀(360) | 評論 (0)編輯 收藏

    2012年11月7日

    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中枚舉實現(xiàn)的分析:

    示例:

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

    顯然,enum很像特殊的class,實際上enum聲明定義的類型就是一個類。 而這些類都是類庫中Enum類的子類(java.lang.Enum<E>)。它們繼承了這個Enum中的許多有用的方法。我們對代碼編譯之 后發(fā)現(xiàn),編譯器將enum類型單獨編譯成了一個字節(jié)碼文件:Color.class。

    Color字節(jié)碼代碼:

    1. final enum hr.test.Color {  
    2.     
    3.  // 所有的枚舉值都是類靜態(tài)常量  
    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.   // 初始化過程,對枚舉類的所有枚舉值對象進(jìn)行第一次初始化  
    13. &nbsp;static {  
    14.        0  new hr.test.Color [1]   
    15.       3  dup  
    16.       4  ldc <String "RED"> [16] //把枚舉值字符串"RED"壓入操作數(shù)棧  
    17.       6  iconst_0  // 把整型值0壓入操作數(shù)棧  
    18.       7  invokespecial hr.test.Color(java.lang.String, int) [17] //調(diào)用Color類的私有構(gòu)造器創(chuàng)建Color對象RED  
    19.      10  putstatic hr.test.Color.RED : hr.test.Color [21]  //將枚舉對象賦給Color的靜態(tài)常量RED。  
    20.       .........  枚舉對象BLUE等與上同  
    21.     102  return 
    22. };  
    23.     
    24.   // 私有構(gòu)造器,外部不可能動態(tài)創(chuàng)建一個枚舉類對象(也就是不可能動態(tài)創(chuàng)建一個枚舉值)。  
    25.  private Color(java.lang.String arg0, int arg1){  
    26.      // 調(diào)用父類Enum的受保護(hù)構(gòu)造器創(chuàng)建一個枚舉對象  
    27.      3  invokespecial java.lang.Enum(java.lang.String, int) [38]  
    28. };  
    29. &nbsp;  
    30.  public static hr.test.Color[] values();  
    31.     
    32.    // 實現(xiàn)Enum類的抽象方法    
    33.   public static hr.test.Color valueOf(java.lang.String arg0);  

    下面我們就詳細(xì)介紹enum定義的枚舉類的特征及其用法。(后面均用Color舉例)

    1、Color枚舉類就是class,而且是一個不可以被繼承的final類。

    其枚舉值(RED,BLUE...)都是Color類型的類靜態(tài)常量, 我們可以通過下面的方式來得到Color枚舉類的一個實例:

    1. Color c=Color.RED;  

    注意:這些枚舉值都是public static final的,也就是我們經(jīng)常所定義的常量方式,因此枚舉類中的枚舉值最好全部大寫。

    2、即然枚舉類是class,當(dāng)然在枚舉類型中有構(gòu)造器,方法和數(shù)據(jù)域。但是,枚舉類的構(gòu)造器有很大的不同:

    (1) 構(gòu)造器只是在構(gòu)造枚舉值的時候被調(diào)用。

     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                     //構(gòu)造枚舉值,比如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;  //自定義數(shù)據(jù)域,private為了封裝。  
    15                     private int greenValue;  
    16                     private int blueValue;  
    17      }

    (2) 構(gòu)造器只能私有private,絕對不允許有public構(gòu)造器。 這樣可以保證外部代碼無法新構(gòu)造枚舉類的實例。這也是完全符合情理的,因為我們知道枚舉值是public static final的常量而已。

    但枚舉類的方法和數(shù)據(jù)域可以允許外部訪問。

    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);  // 調(diào)用了toString()方法  
    6. }     

    3、所有枚舉類都繼承了Enum的方法,下面我們詳細(xì)介紹這些方法。

    (1) ordinal()方法: 返回枚舉值在枚舉類種的順序。這個順序根據(jù)枚舉值聲明的順序而定。

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

    (2) compareTo()方法: Enum實現(xiàn)了java.lang.Comparable接口,因此可以比較象與指定對象的順序。Enum中的compareTo返回的是兩個枚舉值的順 序之差。當(dāng)然,前提是兩個枚舉值必須屬于同一個枚舉類,否則會拋出ClassCastException()異常。(具體可見源代碼)

    1. Color.RED.compareTo(Color.BLUE); //返回結(jié)果 -1 

    (3) values()方法: 靜態(tài)方法,返回一個包含全部枚舉值的數(shù)組。

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

    (4) toString()方法: 返回枚舉常量的名稱。

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

    (5) valueOf()方法: 這個方法和toString方法是相對應(yīng)的,返回帶指定名稱的指定枚舉類型的枚舉常量。

    1. Color.valueOf("BLUE");   //返回結(jié)果: 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 黑螞蟻 閱讀(256) | 評論 (0)編輯 收藏

    hibernate二級緩存攻略

    很多人對二級緩存都不太了解,或者是有錯誤的認(rèn)識,我一直想寫一篇文章介紹一下hibernate的二級緩存的,今天終于忍不住了。
    我的經(jīng)驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。

    hibernate的session提供了一級緩存,每個session,對同一個id進(jìn)行兩次load,不會發(fā)送兩條sql給數(shù)據(jù)庫,但是session關(guān)閉的時候,一級緩存就失效了。

    二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設(shè)置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來說,是根據(jù)ID來找的,緩存的key就是ID,value是POJO。無論list,load還是 iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取數(shù)據(jù)庫select id出來,然后一個id一個id的load,如果在緩存里面有,就從緩存取,沒有的話就去數(shù)據(jù)庫load。假設(shè)是讀寫緩存,需要設(shè)置:
    &lt;cache usage="read-write"/&gt;
    如果你使用的二級緩存實現(xiàn)是ehcache的話,需要配置ehcache.xml
    &lt;cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /&gt;
    其中eternal表示緩存是不是永遠(yuǎn)不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如果 eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發(fā)呆時間,是可選的。當(dāng)往緩存里面put的 元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分?jǐn)?shù)據(jù)保存在硬盤上的臨時文件里面。
    每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然后使用defaultCache的配置,這樣多個class會共享一個配置。
    當(dāng)某個ID通過hibernate修改時,hibernate會知道,于是移除緩存。
    這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什么時候 是第一次,而且每次查詢的條件通常是不一樣的,假如數(shù)據(jù)庫里面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次 iterate的時候卻查詢到30至70號id,那么30-50是從緩存里面取的,51到70是從數(shù)據(jù)庫取的,共發(fā)送1+20條sql。所以我一直認(rèn)為 iterate沒有什么用,總是會有1+N的問題。
    (題外話:有說法說大型查詢用list會把整個結(jié)果集裝入內(nèi)存,很慢,而iterate只select id比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結(jié)果集裝進(jìn)來,假如一頁20條的話,iterate共需要執(zhí)行21條語句,list雖然選擇 若干字段,比iterate第一條select id語句慢一些,但只有一條語句,不裝入整個結(jié)果集hibernate還會根據(jù)數(shù)據(jù)庫方言做優(yōu)化,比如使用mysql的limit,整體看來應(yīng)該還是 list快。)
    如果想要對list或者iterate查詢的結(jié)果緩存,就要用到查詢緩存了

    查詢緩存
    首先需要配置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;
    如果省略第二行,不設(shè)置cacheRegion的話,那么會使用上面提到的標(biāo)準(zhǔn)查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

    對于查詢緩存來說,緩存的key是根據(jù)hql生成的sql,再加上參數(shù),分頁等信息(可以通過日志輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。
    比如hql:
    from Cat c where c.name like ?
    生成大致如下的sql:
    select * from cat c where c.name like ?
    參數(shù)是"tiger%",那么查詢緩存的key*大約*是這樣的字符串(我是憑記憶寫的,并不精確,不過看了也該明白了):
    select * from cat c where c.name like ? , parameter:tiger%
    這樣,保證了同樣的查詢、同樣的參數(shù)等條件下具有一樣的key。
    現(xiàn)在說說緩存的value,如果是list方式的話,value在這里并不是整個結(jié)果集,而是查詢出來的這一串ID。也就是說,不管是list方 法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執(zhí)行一條sql,iterate執(zhí)行1+N條,多出來的 行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據(jù)緩存的key去緩存里面查到了value,value是 一串id,然后在到class的緩存里面去一個一個的load出來。這樣做是為了節(jié)約內(nèi)存。
    可以看出來,查詢緩存需要打開相關(guān)類的class緩存。list和iterate方法第一次執(zhí)行的時候,都是既填充查詢緩存又填充class緩存的。
    這里還有一個很容易被忽視的重要問題,即打開查詢緩存以后,即使是list方法也可能遇到1+N的問題!相同 條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數(shù)據(jù),總是發(fā)送一條sql語句到數(shù)據(jù)庫獲取全部數(shù)據(jù),然后填充查詢緩存和 class緩存。但是第二次執(zhí)行的時候,問題就來了,如果你的class緩存的超時時間比較短,現(xiàn)在class緩存都超時了,但是查詢緩存還在,那么 list方法在獲取id串以后,將會一個一個去數(shù)據(jù)庫load!因此,class緩存的超時時間一定不能短于查詢緩存設(shè)置的超時時間!如果還設(shè)置了發(fā)呆時 間的話,保證class緩存的發(fā)呆時間也大于查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意 了。

    另外,如果hql查詢包含select字句,那么查詢緩存里面的value就是整個結(jié)果集了。

    當(dāng)hibernate更新數(shù)據(jù)庫的時候,它怎么知道更新哪些查詢緩存呢?
    hibernate在一個地方維護(hù)每個表的最后更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
    當(dāng)通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時 間和這個緩存所查詢的表,當(dāng)hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這 些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。
    可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

    Collection緩存
    需要在hbm的collection里面設(shè)置
    &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是根據(jù)某個字段排序的,當(dāng)其中一個元素更新了該字段時,導(dǎo)致順序改變時,collection緩存里面的順序沒有做更新。

    緩存策略
    只讀緩存(read-only):沒有什么好說的
    讀/寫緩存(read-write):程序可能要的更新數(shù)據(jù)
    不嚴(yán)格的讀/寫緩存(nonstrict-read-write):需要更新數(shù)據(jù),但是兩個事務(wù)更新同一條記錄的可能性很小,性能比讀寫緩存好
    事務(wù)緩存(transactional):緩存支持事務(wù),發(fā)生異常的時候,緩存也能夠回滾,只支持jta環(huán)境,這個我沒有怎么研究過

    讀寫緩存和不嚴(yán)格讀寫緩存在實現(xiàn)上的區(qū)別在于,讀寫緩存更新緩存的時候會把緩存里面的數(shù)據(jù)換成一個鎖,其他事務(wù)如果去取相應(yīng)的緩存數(shù)據(jù),發(fā)現(xiàn)被鎖住了,然后就直接取數(shù)據(jù)庫查詢。
    在hibernate2.1的ehcache實現(xiàn)中,如果鎖住部分緩存的事務(wù)發(fā)生了異常,那么緩存會一直被鎖住,直到60秒后超時。
    不嚴(yán)格讀寫緩存不鎖定緩存中的數(shù)據(jù)。


    使用二級緩存的前置條件
    你的hibernate程序?qū)?shù)據(jù)庫有獨占的寫訪問權(quán),其他的進(jìn)程更新了數(shù)據(jù)庫,hibernate是不可能知道的。你操作數(shù)據(jù)庫必需直接通過 hibernate,如果你調(diào)用存儲過程,或者自己使用jdbc更新數(shù)據(jù)庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪 除是不更新二級緩存的,但是據(jù)說3.1已經(jīng)解決了這個問題。
    這個限制相當(dāng)?shù)募?,有時候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優(yōu)化,很郁悶吧。
    SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調(diào)用這些方法移除緩存,這些方法是:
    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.
    不過我不建議這樣做,因為這樣很難維護(hù)。比如你現(xiàn)在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用 evictQueries(String cacheRegion)移除了3個查詢緩存,然后用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關(guān)查詢緩存,可能會忘記更新這里的移除代碼。如果你的 jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什么地方也要做相應(yīng)的改動嗎?

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

    總結(jié):
    不要想當(dāng)然的以為緩存一定能提高性能,僅僅在你能夠駕馭它并且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當(dāng)?shù)氖褂眠€可能導(dǎo)致讀出臟數(shù)據(jù)。
    如果受不了hibernate的諸多限制,那么還是自己在應(yīng)用程序的層面上做緩存吧。
    在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數(shù)據(jù)庫還是要實現(xiàn)自己的緩存,盡管數(shù)據(jù)庫有緩存,咱們的應(yīng)用程序還是要做緩存。因為 底層的緩存它并不知道高層要用這些數(shù)據(jù)干什么,只能做的比較通用,而高層可以有針對性的實現(xiàn)緩存,所以在更高的級別上做緩存,效果也要好些吧。

    ================================================================================
    原文出處:http://www.iteye.com/topic/18904,對hibernate 二級緩存 講解的很徹底,所以轉(zhuǎn)載了,一同分享.

    posted @ 2012-11-07 15:09 黑螞蟻 閱讀(248) | 評論 (0)編輯 收藏

    (按Ctrl+C)選中的table表單中的數(shù)據(jù),粘貼(按Ctrl+V)到目標(biāo)文件(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 黑螞蟻 閱讀(1166) | 評論 (0)編輯 收藏

    2012年10月17日

    svn 紅色感嘆號

    在解決插件與插件的關(guān)系的時候,一個不小心,點擊添加插件的依賴的時候,點到了下面一個插件文件,導(dǎo)致兩個插件相互依賴了,就出現(xiàn)了“svn 紅色感嘆號”標(biāo)記,去掉相互依賴,此問題解決。

    posted @ 2012-10-17 16:04 黑螞蟻 閱讀(934) | 評論 (0)編輯 收藏

    2012年4月24日

    java swt table 點擊表頭排序

    public class PickerShellTableSort {
        private Table table;
        private Image upImage;
        private Image downImage;
        
        private int[] sortFlags;
        private int[] sortColIndexes;
        
        public PickerShellTableSort(Table table) {
            int[] sortCols = new int[table.getColumnCount()];
            for (int i = 1; i < sortCols.length; i++) {
                sortCols[i] = i;
            }
            
            this.table = table;
            this.sortColIndexes = sortCols;     //需要排序的索引
            this.sortFlags = new int[table.getColumnCount()];
            
            init();
        }
        
        private void init() {
            for (int i = 0; i < sortColIndexes.length; i++) {
                final int sortColIndex = this.sortColIndexes[i];
                TableColumn col = table.getColumn(sortColIndex);
                
                col.addListener(SWT.Selection, new Listener() {
                    public void handleEvent(Event event) {
                        columnHandleEvent(event, sortColIndex);
                    }
                });
            }
            
            this.upImage = FrameCommonActivator.getImageDescriptor("icons/up.gif").createImage();
            this.downImage = FrameCommonActivator.getImageDescriptor("icons/down.gif").createImage();
        }
        
        private void columnHandleEvent(Event event, int sortColIndex) {
            try {
                for (int i = 0; i < sortColIndexes.length; i++) {
                    TableColumn tabCol = table.getColumn(i);
                    tabCol.setImage(null);
                }
                
                boolean selectColumnType = this.isStringOrNumberType(sortColIndex);
                
                 if (this.sortFlags[sortColIndex] == 1) {
                     clearSortFlags();
                    this.sortFlags[sortColIndex] = -1;
                    
                    if(selectColumnType) {
                        this.addNumberSorter(table.getColumn(sortColIndex), true);
                    } else {
                        this.addStringSorter(table.getColumn(sortColIndex), true);
                    }
                    
                    table.getColumn(sortColIndex).setImage(this.upImage);
                } else {
                    this.sortFlags[sortColIndex] = 1;
                    
                    if(selectColumnType) {
                        this.addNumberSorter(table.getColumn(sortColIndex), false);
                    } else {
                        this.addStringSorter(table.getColumn(sortColIndex), false);
                    }
                    
                    table.getColumn(sortColIndex).setImage(this.downImage);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        /**
         * @param table
         * @param column
         * @param isAscend  
         */
        private void addStringSorter(TableColumn column,boolean isAscend) {
            
              Collator comparator = Collator.getInstance(Locale.getDefault());
              int columnIndex = getColumnIndex(table, column);
              TableItem[] items = table.getItems();
              //使用冒泡法進(jìn)行排序
              for (int i = 1; i < items.length; i++) {
                  String str2value = items[i].getText(columnIndex);
                  if(str2value.equalsIgnoreCase("")){
                     //當(dāng)遇到表格中的空項目時,就停止往下檢索排序項目
                     break;
                  }
                  for (int j = 0; j < i; j++) {
                     String str1value = items[j].getText(columnIndex);
                     boolean isLessThan = comparator.compare(str2value, str1value) < 0;     
                     if ((isAscend && isLessThan) || (!isAscend && !isLessThan)) {
                          String[] values = getTableItemText(table, items[i]);
                          Object obj = items[i].getData();
                          items[i].dispose();
                          TableItem item = new TableItem(table, SWT.NONE, j);
                          item.setText(values);
                          item.setData(obj);
                          items = table.getItems();
                          break;
                     }
                  }
               }
               table.setSortColumn(column);
               table.setSortDirection((isAscend ? SWT.UP : SWT.DOWN));
               isAscend = !isAscend;
          }
        
        
        private void addNumberSorter(TableColumn column,boolean isAscend) {
            
              int columnIndex = getColumnIndex(table, column);
              TableItem[] items = table.getItems();
              //使用冒泡法進(jìn)行排序
              for (int i = 1; i < items.length; i++) {
               String strvalue2 = items[i].getText(columnIndex);
               if(strvalue2.equalsIgnoreCase("")){
                //當(dāng)遇到表格中的空項目時,就停止往下檢索排序項目
                break;
               }
               
               for (int j = 0; j < i; j++) {
                String strvalue1 = items[j].getText(columnIndex);
                
                //將字符串類型數(shù)據(jù)轉(zhuǎn)化為float類型
                float numbervalue1=Float.valueOf(strvalue1);
                float numbervalue2=Float.valueOf(strvalue2);
                
                boolean isLessThan =false;
                if(numbervalue2<numbervalue1){
                    isLessThan =true;
                }    
                
                if ((isAscend && isLessThan) || (!isAscend && !isLessThan)) {
                     String[] values = getTableItemText(table, items[i]);
                     Object obj = items[i].getData();
                     items[i].dispose();
                     TableItem item = new TableItem(table, SWT.NONE, j);
                     item.setText(values);
                     item.setData(obj);
                     items = table.getItems();
                     break;
                }
               }
              }
              
              table.setSortColumn(column);
              table.setSortDirection((isAscend ? SWT.UP : SWT.DOWN));
              isAscend = !isAscend;
         }
        
        private  int getColumnIndex(Table table, TableColumn column) {
            TableColumn[] columns = table.getColumns();
            for (int i = 0; i < columns.length; i++) {
                if (columns[i].equals(column))
                    return i;
            }
            return -1;
         }
        
        private  String[] getTableItemText(Table table, TableItem item) {
            int count = table.getColumnCount();
            String[] strs = new String[count];
            for (int i = 0; i < count; i++) {
                strs[i] = item.getText(i);
            }
            return strs;
         }

         private void clearSortFlags() {
            for (int i = 0; i < table.getColumnCount(); i++) {
                this.sortFlags[i] = 0;
            }
         }
        
         /**
          * 判斷當(dāng)前選中列的數(shù)據(jù)類型
          * @return
          */
         private boolean isStringOrNumberType(int selectColumnIndex) {
             boolean isok = false ;
            
             TableItem[] items = table.getItems();
             String[] str = new String[items.length];
            
             for (int i = 0; i < items.length; i++) {
                 str[i] = items[i].getText(selectColumnIndex);
             }
            
             for (int i = 0; i < str.length; i++) {
                String string = str[i];
                isok = string.matches("^(-|\\+)?\\d+\\.?\\d*$");
                //如果這一列中有一個是字符串,也按字符串排序
                if(!isok) {
                    return isok;
                }
             }
            
             return isok ;
         }
        
    }

    posted @ 2012-04-24 09:56 黑螞蟻 閱讀(2166) | 評論 (0)編輯 收藏

    僅列出標(biāo)題  下一頁

    導(dǎo)航

    統(tǒng)計

    公告

    路在腳下,此刻,出發(fā)。

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    相冊

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲日本韩国在线| 亚洲国产精华液2020| 免费人成视频x8x8入口| 蜜臀98精品国产免费观看| 一级一片免费视频播放| 亚洲国产综合AV在线观看| 亚洲成a人片在线观看中文!!!| 夜夜春亚洲嫩草影院| 四虎永久在线免费观看| 成人免费视频软件网站| 美女被免费网站在线视频免费| 国产精品免费精品自在线观看| 国产精品免费观看视频| 久久久久亚洲国产AV麻豆| 亚洲一卡2卡3卡4卡乱码 在线| 4480yy私人影院亚洲| 亚洲午夜久久久久妓女影院| 蜜臀91精品国产免费观看| 青青在线久青草免费观看| 美女内射无套日韩免费播放| 青青操免费在线视频| 国产在线播放线91免费| a在线视频免费观看在线视频三区| 毛片亚洲AV无码精品国产午夜| 亚洲一级毛片免费看| 亚洲另类视频在线观看| 亚洲成a人片在线观看中文app| 91亚洲va在线天线va天堂va国产 | 亚洲日本在线免费观看| 亚洲AV无码成人精品区蜜桃| 日韩亚洲一区二区三区| 亚洲国产精品无码久久久蜜芽| 亚洲精品国产字幕久久不卡| 国产成人综合亚洲AV第一页| 亚洲午夜无码久久久久| 国产av无码专区亚洲av桃花庵| 国产亚洲美女精品久久久久狼| 亚洲产国偷V产偷V自拍色戒| 久久亚洲AV无码精品色午夜麻| 亚洲男人的天堂在线播放| 亚洲成aⅴ人片在线观|