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

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

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

    lqxue

    常用鏈接

    統計

    book

    tools

    最新評論

    #

    Print the Stack Trace of the Exception to a String

    import java.io.PrintWriter;
    import java.io.StringWriter;
    public static String getStackTrace(Throwable t)
    {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
    }

    posted @ 2007-04-17 17:24 lqx 閱讀(218) | 評論 (0)編輯 收藏

    spring 管理事務時的pointcut語法

     
    1. execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) 

    其中帶問號的modifiers-pattern?(public/protected) 和 declaring-type-pattern? throws-pattern? 可以不填

    可見execution(* *..BookManager.save(..))

    第一顆* 代表ret-type-pattern 返回值可任意,
    *..BookManager 代表任意Pacakge里的BookManager類。
    如果寫成com.xyz.service.* 則代表com.xyz.service下的任意類
    com.xyz.service..* com.xyz.service則代表com.xyz.service及其子package下的任意類
    save代表save方法,也可以寫save* 代表saveBook()等方法
    (..) 匹配0個參數或者多個參數的,任意類型
    (x,..) 第一個參數的類型必須是X
    (x,,,s,..) 匹配至少4個參數,第一個參數必須是x類型,第二個和第三個參數可以任意,第四個必須是s類型。

    注意name-pattern千萬不要寫成*..*Manager ,這樣子的話會把所有第三方類庫的Manager比如Spring的PlatformTranstationManager 也加入aop,非常危險。所以最好還是加上項目的package前綴,如org.springside

    posted @ 2007-04-17 16:38 lqx 閱讀(265) | 評論 (0)編輯 收藏

    hibernate集合映射inverse和cascade詳解 (轉載)

    4. hibernate如何根據pojo來更新數據庫

    4.0 在commit/flush之前,hibernate不會對pojo對象作神秘的處理。
    4.0.1 在select查詢出pojo時,hibernate根據“字段--屬性”的對應關系,用字段的值填充pojo的屬性;
    然后根據“關系標記”生成sql語句從relationTable中查詢出滿足條件的relationPojo,并把這些relatinPojo
    放到“關系屬性”中。這個過程是機械的。

    4.0.2 在pojo對象被查出來后,到commit(或flush)之前,它將是一個普通的java對象,hibernate不會做額外的手腳。
    比如,不會限制你設置一個屬性的值為null或其它任何值
    在集合類Set的add(object)操作時, 不會改變object的值,不會檢查參數object是否是一個pojo對象
    設置mainPojo的一個“橋屬性”的值,不會自動設置relationPojo的對應的“橋屬性”的值。
    執行session.delete(pojo)時,pojo本身沒有變化,他的屬性值也沒有變化。
    執行session.save(pojo)時,如果pojo的id不是hibernate或數據庫生成,則它的值沒有變化。
    如果pojo的id是hibernate或數據庫生成,則hibernate會把id給pojo設上去。

    extend: 對lazy=true的set,hibernate在進行set的操作(調用java.util.Set中聲明的方法)時
    會先inialize這個set,僅此而已。而inialize僅僅是從數據庫中撈出set的數據。
    如果一個set已經被inialize了,那么對它進行的操作就是java.util.Set接口中定義的語義。

    另外,如果id由hibernate來生成,那么在save(pojo)時,hibernate會改變該pojo,會設置它的id,這
    可能改變該pojo的hashCode,詳細地討論見帖《》

    mapping文件中標記的某些屬性及pojo對象的操作會對數據庫操作產生影響,這些影響都是在commit時才會起作用。
    而在commit前pojo的狀態不受它們的影響。

    不過,待commit之時,將由hibernate完全掌控,它好像知道pojo對象從創建到commit這中間的所有變化。


    4.01. 關聯更新
    "關系標記"對應的屬性是一個pojo或一個pojo的集合,修改“關系屬性”的值能會導致更新mainTable表,也可能會更新relationTable表。

    這種更新暫叫“關聯更新”。


    4.1.inverse屬性的作用(假定沒有設置cascade屬性)
    4.1.1 “只有集合標記(set/map/list/array/bag)才有inverse屬性”。
    ————不妨以標記set為例,具體為“一個地區(Address表)的學校(School表)” -- address.schoolSet。

    4.1.2 “set的inverse屬性決定是否把對set的改動反映到數據庫中去。
    inverse=false————反映;inverse=true————不反映”
    inverse屬性默認為false

    對<one-to-many>和<many-to-many>子標記,這兩條都適用。
    不管是對set做什么操作,4.1.2都適用。

    4.1.3當inverse=false時,hibernate如何將對set的改動反映到數據庫中:

    對set的操作主要有:(1)新增元素 address.getSchoolSet().add(oneSchool);
    (2)刪除元素 address.getSchoolSet().remove(oneSchool);
    (3)刪除set address.setSchoolSet(null);
    (4)設新set address.setSchoolSet( newSchoolSet);
    (5)轉移set otherSchoolSet = otherAddress.getSchoolSet();
    otherAddress.setSchoolSet(null);
    address.setSchoolSet(otherSchoolSet);
    (6)改變set中元素的屬性的值 如果是改變key屬性,這會導致異常
    如果改變的是普通的屬性,則hibernate認為set沒有變化(在后面可以看出緣由)。
    所以這種情形不予考慮。

    改變set后,hibernate對數據庫的操作根據是<one-to-many>關系還是<many-to-many>關系而有不同。

    對one-to-many,對school set的改動,會改變表SCHOOL中的數據:
    #SCHOOL_ID是school表的主鍵,SCHOOL_ADDRESS是school表中的地址欄位
    #表School的外鍵為SCHOOL_ADDRESS,它對應表Address的主鍵ADDRESS_ID
    (11)insert oneSchool———— sqlInsertRowString:
    update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=?
    (僅僅update foreign-key的值。)
    (22)delete oneSchool———— sqlDeleteRowString:
    update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?
    (很奇怪,把foreign-key設置為null不知道有什么實際意義?)
    (33)delete 屬于某一address的所有school ————sqlDeleteString:
    update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?
    (44)update ————sqlUpdateRowString:"", no need

    對many-to-many,對school set的改動,會改變關系表ADDRESS_SCHOOL中的數據:
    #“地區————學校”的關系為多對多的關系有點牽強,只是為了方便與上面的one-to-many作比較
    #假設有一個關系表ADDRESS_SCHOOL,有兩個字段ADDRESS_ID, SCHOOL_ID,
    #這兩個字段分別對應ADDRESS和SCHOOL兩表的key
    (11)insert的SQL語句為: insert into ADDRESS_SCHOOL(ADDRESS_ID, SCHOOL_ID)
    values(?,?)
    (22)delete的SQL語句為: delete from ADDRESS_SCHOOL
    where ADDRESS_ID=? AND SCHOOL_ID=?
    (33)delete all的SQL語句為: delete from ADDRESS_SCHOOL
    where ADDRESS_ID=?
    (44)update的sql語句為 ————sqlUpdateRowString:
    update ADDRESS_SCHOOL set ADDRESS_ID=?
    where ADDRESS_ID=? AND SCHOOL_ID=?

    對set的操作(1),hibernate會執行(11)sqlInsertRowString
    對set的操作(2),hibernate會執行(22)sqlDeleteRowString
    對set的操作(3),hibernate會執行(33)sqlDeleteString
    對set的操作(4),老的schoolSet因為沒有所屬的address,所以被全部delete掉,即先執行(33)sqlDeleteString
    然后新增新的schoolSet,即再執行sqlInsertRowString
    對set的操作(5),實際上就是將set從一個pojo轉移到另一pojo:
    首先,執行sqlDeleteString,刪除掉otherAddress所屬的school
    然后,執行sqlDeleteString,刪除掉address原先的school
    最后,執行sqlInsertRowString,將otherSchoolSet新增給address

    總結:(1)對one-to-many而言,改變set,會讓hibernate執行一系列的update語句, 不會delete/insert數據
    (2)對many-to-many而言,改變set,只修改關系表的數據,不會影響many-to-many的另一方。
    (3)雖然one-to-many和many-to-many的數據庫操作不一樣,但目的都是一個:維護數據的一致性。執行的sql都
    只涉及到“橋字段”,不會考慮或改變其他的字段,所以對set的操作(6)是沒有效果地。
    extend:對list,可能還會維護index字段。

    4.1.4 “inverse與cascade沒有什么關系,互無牽扯。”
    commit后,這兩個屬性發揮作用的時機不同,hibernate會根據對pojo對象的改動,及cascade屬性的設置,
    生成一系列的Action,比如UpdateAction,DeleteAction,InsertAction等,每個Action都有execute方法以執行對應的sql語句。
    待所有這些Action都生成好了后,hibernate再一起執行它們,在執行sql前,inverse屬性起作用,
    當inverse=true時,不執行sql;當inverse=false時,執行sql。

    4.1.5 inverse的默認值為false,所以inverse屬性默認會進行“關聯更新”。

    4.1.6 建議:只對set + many-to-many設置inverse=false,其他的標記不考慮inverse屬性。
      糟糕的是,不設置inverse屬性時,inverse默認為false。

    4.2. 級聯(cascade)屬性的作用:
    4.2.1 只有“關系標記”才有cascade屬性:many-to-one,one-to-one ,any,
    set(map, bag, idbag, list, array) + one-to-many(many-to-many)

    4.2.2 級聯指的是當主控方執行操作時,關聯對象(被動方)是否同步執行同一操作。
    pojo和它的關系屬性的關系就是“主控方 -- 被動方”的關系,如果關系屬性是一個set,那么被動方就是set中的一個一個元素,。
    比如:學校(School)有三個屬性:地區(Address),校長(TheMaster)和學生(Set, 元素為Student)
    執行session.delete(school)時,級聯決定是否執行session.delete(Address),session.delete(theMaster),
    是否對每個aStudent執行session.delete(aStudent)。

    extend:這點和inverse屬性是有區別的。見4.3.

    4.2.3 一個操作因級聯cascade可能觸發多個關聯操作。前一個操作叫“主控操作”,后一個操作叫“關聯操作”。
    cascade屬性的可選值:
    all : 所有情況下均進行關聯操作。
    none:所有情況下均不進行關聯操作。這是默認值。
    save-update:在執行save/update/saveOrUpdate時進行關聯操作。
    delete:在執行delete時進行關聯操作。

    具體執行什么“關聯操作”是根據“主控操作”來的:
    “主控操作”       “關聯操作”
    session.saveOrUpdate --> session.saveOrUpdate (執行saveOrUpdate實際上會執行save或者update)
    session.save ----> session.saveOrUpdate
    session.udpate --> session.saveOrUpdate
    session.delete --> session.delete

    4.2.4 主控操作和關聯操作的先后順序是“先保存one,再保存many;先刪除many,再刪除one;先update主控方,再update被動方”
    對于one-to-one,當其屬性constrained="false"(默認值)時,它可看作one-to-many關系;
      當其屬性constrained="true"時,它可看作many-to-one關系;
    對many-to-many,它可看作one-to-many。

    比如:學校(School)有三個屬性:地區(Address),校長(TheMaster,其constrained="false")和學生(Set, 元素為Student)
    當執行session.save(school)時,
    實際的執行順序為:session.save(Address);
    session.save(school);
    session.save(theMaster);
    for( 對每一個student ){
    session.save(aStudent);
    }

    當執行session.delete(school)時,
    實際的執行順序為:session.delete(theMaster);
    for( 對每一個student ){
    session.delete(aStudent);
    }
    session.delete(school);
    session.delete(Address);

    當執行session.update(school)時,
    實際的執行順序為:session.update(school);
    session.saveOrUpdate(Address);
    session.saveOrUpdate(theMaster);
    for( 對每一個student ){
    session.saveOrUpdate(aStudent);
    }
    注意:update操作因級聯引發的關聯操作為saveOrUpdate操作,而不是update操作。
    saveOrUpdate與update的區別是:前者根據操作對象是保存了還是沒有保存,而決定執行update還是save

    extends: 實際中,刪除學校不會刪除地區,即地區的cascade一般設為false
    另外,many-to-many關系很少設置cascade=true,而是設置inverse=false。這個反映了cascade和inverse的區別。見4.3

    4.2.6 cascade的默認值為false,所以inverse屬性默認會進行“關聯更新”。

    4.2.7 總結:級聯(cascade)就是操作一個對象時,對它的屬性(其cascade=true)也進行這個操作。


    4.3 inverse和cascade的比較
    這兩個屬性本身互不影響,但起的作用有些類似,都能引發對關系表的更新。

    4.3.1 inverse只對set+one-to-many(或many-to-many)有效,對many-to-one, one-to-one無效。
    cascade對關系標記都有效。

    4.3.2 inverse對集合對象整體起作用,cascade對集合對象中的一個一個元素起作用,如果集合為空,那么cascade不會引發關聯操作。
    比如將集合對象置為null, school.setStudentSet(null)
    inverse導致hibernate執行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
    cascade則不會執行對STUDENT表的關聯更新, 因為集合中沒有元素。

    再比新增一個school, session.save(school)
    inverse導致hibernate執行:
    for( 對(school的每一個student ){
    udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //將學生的school_id改為新的school的id
    }
    cascade導致hibernate執行:
    for( 對school的每一個student ){
    session.save(aStudent); //對學生執行save操作
    }

    extends:如果改變集合中的部分元素(比如新增一個元素),
    inverse: hibernate先判斷哪些元素改變了,對改變的元素執行相應的sql
    cascade: 它總是對集合中的每個元素執行關聯操作。
    (在關聯操作中,hibernate會判斷操作的對象是否改變)

    4.3.2 兩個起作用的時機不同:
    cascade:在對主控方操作時,級聯發生。
    inverse: 在flush時(commit會自動執行flush),對session中的所有set,hibernate判斷每個set是否有變化,
    對有變化的set執行相應的sql,執行之前,會有個判斷:if( inverse == true ) return;

    可以看出cascade在先,inverse在后。

    4.3.3 inverse 對set + one-to-many 和 set + many-to-many 起的作用不同。hibernate生成的sql不同。
    對one-to-many,hibernate對many方的數據庫表執行update語句。
    對many-to-many, hibernate對關系表執行insert/update/delte語句,注意不是對many方的數據庫表而是關系表。

    cascase 對set都是一致的,不管one-to-many還是many-to-many。都簡單地把操作傳遞到set中的每個元素。所以它總是更新many
    方的數據庫表。

    4.3.4 建議:只對set + many-to-many設置inverse=false,其他的標記不考慮inverse屬性,都設為inverse=true。
     
      對cascade,一般對many-to-one,many-to-many,constrained=true的one-to-one 不設置級聯刪除。

    引自:http://bbs.tech.ccidnet.com/simple/index.php?t144447.html

    posted @ 2007-04-13 13:19 lqx 閱讀(396) | 評論 (0)編輯 收藏

    Spring AOP處理日志

    Spring AOP處理日志

    AOP正在成為軟件開發的下一個圣杯。使用AOP,你可以將處理aspect的代碼注入主程序,
    通常主程序的主要目的并不在于處理這些aspect。AOP可以防止代碼混亂。 為了理解AOP
    如何做到這點,考慮一下記日志的工作。日志本身不太可能是你開發的主程序的主要任務。
    如果能將“不可見的”、通用的日志代碼注入主程序中,那該多好啊。AOP可以幫助你做到。
    Spring framework是很有前途的AOP技術。作為一種非侵略性的,輕型的AOP framework,你
    無需使用預編譯器或其他的元標簽,便可以在Java程序中使用它。這意味著開發團隊里只需
    一人要對付AOP framework,其他人還是象往常一樣編程。 AOP是很多直覺難以理解的術語的根源。
    幸運的是,你只要理解三個概念,就可以編寫AOP模塊。這三個概念是:advice,pointcut和advisor。
    advice是你想向別的程序內部不同的地方注入的代碼。pointcut定義了需要注入advice的位置,通常
    是某個特定的類的一個public方法。advisor是pointcut和advice的裝配器,是將advice注入主程序
    中預定義位置的代碼。

    既然我們知道了需要使用advisor向主要代碼中注入“不可見的”advice,讓我們實現一個Spring AOP的例子。
    在這個例子中,我們將實現一個before advice,這意味著advice的代碼在被調用的public方法開始前被執行。
    以下是這個before advice的實現代碼:

    代碼:
    package com.company.springaop.test;

    import java.lang.reflect.Method;
    import org.springframework.aop.MethodBeforeAdvice;

    public class TestBeforeAdvice implements MethodBeforeAdvice { //這里還有after,Exception,around等Advice
    /**
    *before 是在方法執行之前執行advice的內容,around是在方法執行之前和之后都得到了執行
    *Exception是拋出異常的時候,可以使用aop的方法來統一處理業務的異常。
    ×在編程的時候,可以由專門的人處理業務的異常,其它人還是一樣的編程,不用考慮業務類異常的處理。
    */

      public void before(Method m, Object[] args, Object target)
      throws Throwable { //這里能用反射?
        System.out.println("Hello world! (by "
            + this.getClass().getName()
            + ")");
      }
    }
     


    接 口MethodBeforeAdvice只有一個方法before需要實現,它定義了advice的實現。before方法共用三個參數,它們提供了相當 豐富的信息。參數Method m是advice開始后執行的方法。方法名稱可以用作判斷是否執行代碼的條件。Object[] args是傳給被調用的public方法的參數數組。當需要記日志時,參數args和被執行方法的名稱,都是非常有用的信息。你也可以改變傳給m的參數, 但要小心使用這個功能;編寫最初主程序的程序員并不知道主程序可能會和傳入參數的發生沖突。Object target是執行方法m對象的引用。

    在下面的BeanImpl類中,每個public方法調用前,都會執行advice:

    代碼:
    package com.company.springaop.test;

    public class BeanImpl implements Bean {

      public void theMethod() {
        System.out.println(this.getClass().getName()
            + "." + new Exception().getStackTrace()[0].getMethodName()
            + "()"
            + " says HELLO!");
      }
    }


    類BeanImpl實現了下面的接口Bean:

    代碼:
    package com.company.springaop.test;

    public interface Bean {
      public void theMethod();
    }

     

    雖然不是必須使用接口,但面向接口而不是面向實現編程是良好的編程實踐,Spring也鼓勵這樣做。

    pointcut和advice通過配置文件來實現,因此,接下來你只需編寫主方法的Java代碼:
    代碼:


    package com.company.springaop.test;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;

    public class Main {

      public static void main(String[] args) {
        //Read the configuration file
        ApplicationContext ctx
            = new FileSystemXmlApplicationContext("springconfig.xml");

        //Instantiate an object
        Bean x = (Bean) ctx.getBean("bean");

        //Execute the public method of the bean (the test)
        x.theMethod();
      }
    }

     

    我們從讀入和處理配置文件開始,接下來馬上要創建它。這個配置文件將作為粘合程序不同部分的“膠水”。讀入和處理配置文件后,我們會得到一個創建工廠ctx。任何一個Spring管理的對象都必須通過這個工廠來創建。對象通過工廠創建后便可正常使用。

    僅僅用配置文件便可把程序的每一部分組裝起來。
    代碼:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN" "

    <beans>
      <!--CONFIG-->
      <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces">
          <value>com.company.springaop.test.Bean</value>
        </property>
        <property name="target">
          <ref local="beanTarget"/>
        </property>
        <property name="interceptorNames">
          <list>
            <value>theAdvisor</value>
          </list>
        </property>
      </bean>

      <!--CLASS-->
      <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/>

      <!--ADVISOR-->
      <!--Note: An advisor assembles pointcut and advice-->
      <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
          <ref local="theBeforeAdvice"/>
        </property>
        <property name="pattern"> //pointcut?
          <value>com\.company\.springaop\.test\.Bean\.theMethod</value>
        </property>
      </bean>

      <!--ADVICE-->
      <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/>
    </beans>
     


    四個bean定義的次序并不重要。我們現在有了一個advice,一個包含了正則表達式pointcut的advisor,
    一個主程序類和一個配置好的接口,通過工廠ctx,這個接口返回自己本身實現的一個引用。 BeanImpl
    和TestBeforeAdvice都是直接配置。我們用一個唯一的ID創建一個bean元素,并指定了一個實現類。這
    就是全部的工作。advisor通過Spring framework提供的一個RegexMethodPointcutAdvisor類來實現。我
    們用advisor的一個屬性來指定它所需的advice-bean。第二個屬性則用正則表達式定義了pointcut,確保
    良好的性能和易讀性。 最后配置的是bean,它可以通過一個工廠來創建。bean的定義看起來比實際上要
    復雜。bean是ProxyFactoryBean的一個實現,它是Spring framework的一部分。這個bean的行為通過一下
    的三個屬性來定義:

     


    屬性proxyInterface定義了接口類。

    屬性target指向本地配置的一個bean,這個bean返回一個接口的實現。

    屬性interceptorNames是唯一允許定義一個值列表的屬性。這個列表包含所有需要在beanTarget上執行的advisor。

    注意,advisor列表的次序是非常重要的。

     

    Spring工具

    雖然你可以手工修改Ant構建腳本,但使用SpringUI(譯注:SpringUI現在是Spring framework的一部分,并改名
    為spring-ide),使用Spring AOP變得很簡單,只要點點鼠標即可。你可以把SpringUI安裝成Eclipse的一個plug-in。
    然后,你只需在你的project上右擊鼠標,并選擇“add Spring Project Nature”。在project屬性中,你可以在“Spring
    Project”下添加Spring配置文件。在編譯前把下面的類庫加入project:aopalliance.jar,commons-logging.jar,
    jakarta-oro-2.0.7.jar和spring.jar。運行程序時你會看到下面的信息:

    ... (logging information)
    Hello world! (by com.company.springaop.test.TestBeforeAdvice)
    com.company.springaop.test.BeanImpl.theMethod() says HELLO!


    優點和缺點

    Spring比起其他的framework更有優勢,因為除了AOP以外,它提供了更多別的功能。
    作為一個輕型framework,它在J2EE不同的部分都可以發揮作用。因此,即使不想使用Spring AOP,
    你可能還是想使用Spring。另一個優點是,Spring并不要求開發團隊所有的人員都會用它。
    學習Spring應該從Spring reference的第一頁開始。讀了本文后,你應該可以更好地理解Spring reference了。
    Spring唯一的缺點是缺乏更多的文檔,但它的mailing list是個很好的補充,而且會不斷地出現更多的文檔。


    (引自http://blogger.org.cn/blog/more.asp?name=littcricket&id=18341)




    posted @ 2007-04-09 16:23 lqx 閱讀(942) | 評論 (0)編輯 收藏

    Hibernate Transaction

    http://www.tkk7.com/goingmm/archive/2005/11/28/21642.html

    posted @ 2007-04-06 17:21 lqx 閱讀(102) | 評論 (0)編輯 收藏

    (轉)Hibernate Transaction

    Hibernate Transaction

    posted @ 2007-04-06 17:20 lqx 閱讀(135) | 評論 (0)編輯 收藏

    數據庫事務和鎖

    簡述

        關系型數據庫有四個顯著的特征,即安全性、完整性、并發性和監測性。數據庫的安全性就是要保證數據庫中數據的安全,防止未授權用戶隨意修改數據庫中的數 據,確保數據的安全。在大多數數據庫管理系統中,主要是通過許可來保證數據庫的安全性。完整性是數據庫的一個重要特征,也是保證數據庫中的數據切實有效、 防止錯誤、實現商業規則的一種重要機制。在數據庫中,區別所保存的數據是無用的垃圾還是有價值的信息,主要是依據數據庫的完整性是否健全。在SQL Server 7.0中,數據的完整性是通過一系列邏輯來保障的,這些邏輯分為三個方面,即實體完整性、域完整性和參考完整性。對任何系統都可以這樣說,沒有監測,就沒 有優化。這句話用在數據庫管理系統方面,也是切合實際的。只有通過對數據庫進行全面的性能監測,也才能發現影響系統性能的因素和瓶頸,才能針對瓶頸因素, 采取切合實際策略,解決問題,提高系統的性能。并發性也是一個非常重要的概念,它是用來解決多個用戶對同一數據進行操作時的問題。特別是對于網絡數據庫來 說,這個特點更加突出。提高數據庫的處理速度,單單依靠提高計算機的物理速度是不夠的,還必須充分考慮數據庫的并發性問題,提高數據庫并發性的效率。那么 如何保證并發性呢?在這個面向下一世紀的數據庫產品SQL Server 7.0中,通過使用事務和鎖機制,解決了數據庫的并發性問題。

    事 務和鎖是兩個緊密聯系的概念事務就是一個單元的工作,包括一系列的操作這些操作要么全部成功,要么全部失敗。事務確保多個數據的修改作為一個單元來處 理。例如,在銀行業務中,有一條記帳原則,即有借有貸,借貸相等。那么為了保證這種原則,就得有確保借和貸的登記要么同時成功,要么同時失敗。如果出現只 記錄了借,或者只記錄了貸,那么就違反了記帳原則,就會出現記錯帳的情況。SQL Server通過支持事務機制管理多個事務,保證事務的一致性。事務使用鎖,防止其他用戶修改另外一個還沒有完成的事務中的數據。對于多用戶系統來說,鎖 機制是必須的。在SQL Server 7.0中,使用事務日志來保證修改的完整性和可恢復性。

        SQL Server有多種鎖,允許事務鎖定不同的資源。鎖就是保護指定的資源,不被其他事務操作。為了最小化鎖的成本,SQL Server自動地以與任務相應等級的鎖來鎖定資源對象。鎖定比較小的對象,例如鎖定行,雖然可以提高并發性,但是卻有較高的開支,因為如果鎖定許多行, 那么需要占有更多的鎖。鎖定比較大的對象,例如鎖定表,會大大降低并發性,因為鎖定整個表就限制了其他事務訪問該表的其他部分,但是成本開支比較低,因為 只需維護比較少的鎖。

        事務和鎖具有以下特點:

    • 事務是一個單元的工作,要么全做,要么全不做
    • 事務保證操作的一致性和可恢復性
    • 每一條Transact-SQL語句都可以是一個事務
    • 實際使用的事務是用戶定義的事務,它包括一系列操作或者語句
    • 在多服務器環境中,使用用戶定義的分布式事務,保證操作的一致性
    • 鎖是保證并發控制的手段
    • 可以鎖定的資源包括行、頁、簇、表和數據庫
    • 鎖的類型主要包括共享鎖和排它鎖
    • 特殊類型的鎖包括意圖鎖、修改鎖和模式鎖
    • 共享鎖允許其他事務繼續使用鎖定的資源
    • 排它鎖只允許一個事務訪問數據
    • 系統本身可以處理死鎖
    • 用戶可以根據實際情況定制鎖的一些特征

    事務

    事務的定義

        事務是指一個單元的工作,這些工作要么全做,要么全部不做。作為一個邏輯單元,必須具備四個屬性:原子性、一致性、獨立性和持久性。原子性是指事務必須是 一個自動的單元工作,要么執行全部數據的修改,要么全部數據的修改都不執行。一致性是指當事務完成時,必須使所有數據都具有一致的狀態。在關系型數據庫 中,所有的規則必須應用到事務的修改上,以便維護所有數據的完整性。所有的內部數據結構,例如樹狀的索引與數據之間的鏈接,在事務結束之后,必須保證正 確。獨立性是指并行事務的修改必須與其他并行事務的修改相互獨立。一個事務看到的數據要么是另外一個事務修改這些事務之前的狀態,要么是第二個事務已經修 改完成的數據,但是這個事務不能看到正在修改的數據。這種特征也稱為串行性。持久性是指當一個事務完成之后,它的影響永久性的產生在系統中,也就是這種修 改寫到了數據庫中。

        事務機制保證一組數據的修改要么全部執行,要么全部不執行。SQL Server使用事務保證數據的一致性和確保在系統失敗時的可恢復性。事務是一個可以恢復的單元的工作,由一條或者多條Transact-SQL語句組 成,可以影響到表中的一行或者多行數據。事務打開以后,直到事務成功完成之后提交為止,或者到事務執行失敗全部取消或者滾回去為止。



    悲觀鎖定 假定任何時刻存取數據時,都可能有另一個客戶也正在存取同一筆數據,因而對數據采取了數據庫層次的鎖定狀態,在鎖定的時間內其它的客戶不能對資 料進行存取,對于單機或小系統而言,這并不成問題,然而如果是在網絡上的系統,同時間會有許多聯機,如果每一次讀取數據都造成鎖定,其后繼的存取就必須等 待,這將造成效能上的問題,造成后繼使用者的長時間等待。
    樂觀鎖定(optimistic locking)則樂觀的認為資料的存取很少發生同時存取的問題,因而不作數據庫層次上的鎖定,為了維護正確的數據,樂觀鎖定使用應用程序上的邏輯實現版本控制的解決。
    例如若有兩個客戶端,A客戶先讀取了賬戶余額1000元,之后B客戶也讀取了賬戶余額1000元的數據,A客戶提取了500元,對數據庫作了變更,此時 數據庫中的余額為500元,B客戶也要提取300元,根據其所取得的資料,1000-300將為700余額,若此時再對數據庫進行變更,最后的余額就會不 正確。
    在不實行悲觀鎖定策略的情況下,數據不一致的情況一但發生,有幾個解決的方法,一種是先更新為主,一種是后更新的為主,比較復雜的就是檢查發生變動的數據來實現,或是檢查所有屬性來實現樂觀鎖定。

     

    posted @ 2007-04-06 16:57 lqx 閱讀(391) | 評論 (0)編輯 收藏

    (轉載)關于hibernate中的鎖機制

    前幾天看到GOING MM關于Hibernate Transaction 的描述,這里順便轉載一篇hiberntae中鎖機制的文章:

       悲觀鎖定 假定任何時刻存取數據時,都可能有另一個客戶也正在存取同一筆數據,因而對數據采取了數據庫層次的鎖定狀態,在鎖定的時間內其它的客戶不能對資 料進行存取,對于單機或小系統而言,這并不成問題,然而如果是在網絡上的系統,同時間會有許多聯機,如果每一次讀取數據都造成鎖定,其后繼的存取就必須等 待,這將造成效能上的問題,造成后繼使用者的長時間等待。
     樂觀鎖定(optimistic locking)則樂觀的認為資料的存取很少發生同時存取的問題,因而不作數據庫層次上的鎖定,為了維護正確的數據,樂觀鎖定使用應用程序上的邏輯實現版本控制的解決。
    例如若有兩個客戶端,A客戶先讀取了賬戶余額1000元,之后B客戶也讀取了賬戶余額1000元的數據,A客戶提取了500元,對數據庫作了變更,此時 數據庫中的余額為500元,B客戶也要提取300元,根據其所取得的資料,1000-300將為700余額,若此時再對數據庫進行變更,最后的余額就會不 正確。
     在不實行悲觀鎖定策略的情況下,數據不一致的情況一但發生,有幾個解決的方法,一種是先更新為主,一種是后更新的為主,比較復雜的就是檢查發生變動的數據來實現,或是檢查所有屬性來實現樂觀鎖定。
     Hibernate 中透過版本號檢查來實現后更新為主,這也是Hibernate所推薦的方式,在數據庫中加入一個VERSON欄記錄,在讀取數據時連 同版本號一同讀取,并在更新數據時遞增版本號,然后比對版本號與數據庫中的版本號,如果大于數據庫中的版本號則予以更新,否則就回報錯誤。
     以剛 才的例子,A客戶讀取賬戶余額1000元,并連帶讀取版本號為5的話,B客戶此時也讀取賬號余額1000元,版本號也為5,A客戶在領款后賬戶余額 為500,此時將版本號加1,版本號目前為6,而數據庫中版本號為5,所以予以更新,更新數據庫后,數據庫此時余額為500,版本號為6,B客戶領款后要 變更數據庫,其版本號為5,但是數據庫的版本號為6,此時不予更新,B客戶數據重新讀取數據庫中新的數據并重新進行業務流程才變更數據庫。
     以Hibernate實現版本號控制鎖定的話,我們的對象中增加一個version屬性,例如:

    public class Account {

        private int version;

        ....

     

        public void setVersion(int version) {

            this.version = version;

        }

     

        public int getVersion() {

            return version;

        }

        ....

    }


    而在映像文件中,我們使用optimistic-lock屬性設定version控制,<id>屬性欄之后增加一個<version>標簽,例如:

    <hibernate-mapping>

        <class name="onlyfun.caterpillar.Account" talble="ACCOUNT"

               optimistic-lock="version">

            <id...../>

            <version name="version" column="VERSION"/>

     

             ....

     

        </class>

    </hibernate-mapping>


     設定好版本控制之后,在上例中如果B 客戶試圖更新數據,將會引發StableObjectStateException例外,我們可以捕捉這個例外,在處理中重新讀取數據庫中的數據,同時將 B客戶目前的數據與數據庫中的數據秀出來,讓B客戶有機會比對不一致的數據,以決定要變更的部份,或者您可以設計程 式自動讀取新的資料,并重復扣款業務流程,直到數據可以更新為止,這一切可以在背景執行,而不用讓您的客戶知道。


      悲觀鎖定
    在多個客戶端可能讀取同一筆數據或同時更新一筆數據的情況下,必須要有訪問控制的手段,防止同一個數據被修改而造成混亂,最簡單的手段就是對數據進行鎖定,在自己進行數據讀取或更新等動作時,鎖定其它客戶端不能對同一筆數據進行任何的動作。
     悲觀鎖定(Pessimistic Locking)一如其名稱所示,悲觀的認定每次資料存取時,其它的客戶端也會存取同一筆數據,因此對該筆數據進行鎖定,直到自己操作完成后解除鎖定。

     悲觀鎖定通常透過系統或數據庫本身的功能來實現,依賴系統或數據庫本身提供的鎖定機制,Hibernate即是如此,我們可以利用Query或Criteria的setLockMode()方法來設定要鎖定的表或列(row)及其鎖定模式,鎖定模式有以下的幾個:

    • LockMode.WRITE:在insert或update時進行鎖定,Hibernate會在save()方法時自動獲得鎖定。
    • LockMode.UPGRADE:利用SELECT … FOR UPDATE進行鎖定。
    • LockMode.UPGRADE_NOWAIT:利用SELECT … FOR UPDATE NOWAIT進行鎖定,在Oracle環境下使用。
    • LockMode.READ:在讀取記錄時Hibernate會自動獲得鎖定。
    • LockMode.NONE:沒有鎖定。

     也可以在使用Session的load()或是lock()時指定鎖定模式以進行鎖定。
     如果數據庫不支持所指定的鎖定模式,Hibernate會選擇一個合適的鎖定替換,而不是丟出一個例外(Hibernate參考手冊10.6)。

      原文出處:http://blog.csdn.net/chho/archive/2005/01.aspx

    posted @ 2007-04-06 16:13 lqx 閱讀(177) | 評論 (0)編輯 收藏

    為什么在hibernate中用list影射one-to-many時,在查詢數據時,經常有null值

     Learned a little this weekend - Bag vs List in Hibernate.  I was troubled since i really wanted to have a Java ArrayList in my object so i could index in my jsp and iterate over the list in an update form.  Using a Hibernate Set left me unable to index.  A Hibernate List left the Java ArrayList populated using the primary key - if the keys were 0,1,2,... that would have been ok.  But i only needed a few items from the database in my ArrayList and since the Hibernate List maintains the position of the object in the ArrayList equal to the position in the database the technique was leaving holes in my ArrayList of nulls.  Of course this was not what i wanted.  Now this may be explained in the documentation but after reading it twice i did not fully understand the Hibernate List.  Over the weekend i read the book Hibernate in Action and discovered the Hibernate Bag and it solved my problem.  I can use a Java ArrayList that is loaded simply by adding new objects to the beginning of the ArrayList.

    posted @ 2007-04-05 16:50 lqx 閱讀(3067) | 評論 (1)編輯 收藏

    Open Session In View

    http://www.54bk.com/user1/2690/archives/2006/2006122116259.html

    Open Session In View解決session.close問題
    ssuupv 發表于 2006-12-21 16:25:00
      在沒有使用Spring提供的Open Session In View情況下,因需要在service(or Dao)層里把session關閉,所以lazy loading true的話,要在應用層內把關系集合都初始化,如 company.getEmployees(),否則Hibernatesession already closed Exception;    Open Session In View提供了一種簡便的方法,較好地解決了lazy loading問題.

        它有兩種配置方式OpenSessionInViewInterceptorOpenSessionInViewFilter(具體參看SpringSide),功能相同,只是一個在web.xml配置,另一個在application.xml配置而已。

        Open Session In Viewrequestsession綁定到當前thread期間一直保持hibernate sessionopen狀態,使sessionrequest的整個期間都可以使用,如在View層里PO也可以lazy loading數據,如 ${ company.employees }。當View 層邏輯完成后,才會通過FilterdoFilter方法或InterceptorpostHandle方法自動關閉session

                            
    OpenSessionInViewInterceptor配置
    1. <beans>
    2. <bean name="openSessionInViewInterceptor"
    3. class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    4. <property name="sessionFactory">
    5. <ref bean="sessionFactory"/>
    6. </property>
    7. </bean>
    8. <bean id="urlMapping"
    9. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    10. <property name="interceptors">
    11. <list>
    12. <ref bean="openSessionInViewInterceptor"/>
    13. </list>
    14. </property>
    15. <property name="mappings">
    16. ...
    17. </property>
    18. </bean>
    19. ...
    20. </beans>
                            
    OpenSessionInViewFilter配置
    1. <web-app>
    2. ...
    3. <filter>
    4. <filter-name>hibernateFilter</filter-name>
    5. <filter-class>
    6. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    7. </filter-class>
    8. <!-- singleSession默認為true,若設為false則等于沒用OpenSessionInView -->
    9. <init-param>
    10. <param-name>singleSession</param-name>
    11. <param-value>true</param-value>
    12. </init-param>
    13. </filter>
    14. ...
    15. <filter-mapping>
    16. <filter-name>hibernateFilter</filter-name>
    17. <url-pattern>*.do</url-pattern>
    18. </filter-mapping>
    19. ...
    20. </web-app>

    很多人在使用OpenSessionInView過程中提及一個錯誤:

                            
    1. org.springframework.dao.InvalidDataAccessApiUsageException: Write operations
    2. are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into
    3. FlushMode.AUTO or remove 'readOnly' marker from transaction definition

    看看OpenSessionInViewFilter里的幾個方法

                            
    1. protected void doFilterInternal(HttpServletRequest request,
      HttpServletResponse response,FilterChain filterChain)
      throws ServletException, IOException {
       SessionFactory sessionFactory = lookupSessionFactory();
       logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
       Session session = getSession(sessionFactory);
       TransactionSynchronizationManager.bindResource(
        sessionFactory, new SessionHolder(session));
       try {
        filterChain.doFilter(request, response);
       }
       finally {
       TransactionSynchronizationManager.unbindResource(sessionFactory);
       logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
       closeSession(session, sessionFactory);
       }
      }





       
    2. protected Session getSession(SessionFactory sessionFactory)
      throws DataAccessResourceFailureException {
       Session session = SessionFactoryUtils.getSession(sessionFactory, true);
       session.setFlushMode(FlushMode.NEVER);
       return session;
      }

    3. protected
      void closeSession(Session session, SessionFactory sessionFactory)
      throws CleanupFailureDataAccessException {
       SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);
      }

         可以看到OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設為FlushMode.NEVER。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過后再接除該sessionFactory的綁定,最后closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。在這個過程中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權限。

                            
    1. public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)
    2. throws CleanupFailureDataAccessException {
    3. if (session == null ||
      TransactionSynchronizationManager.hasResource(sessionFactory)) {
    4. return;
    5. }
    6. logger.debug("Closing Hibernate session");
    7. try {
    8. session.close();
    9. }
    10. catch (JDBCException ex) {
    11. // SQLException underneath
    12. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());
    13. }
    14. catch (HibernateException ex) {
    15. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex);
    16. }
    17. }

        也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉為Flush.AUTO,擁有insert,update,delete操作權限,如果沒有transaction,并且沒有另外人為地設flush model的話,則doFilter的整個過程都是Flush.NEVER。所以受transaction保護的方法有寫權限,沒受保護的則沒有。

                            
    采用spring的事務聲明,使方法受transaction控制
    1.   <bean id="baseTransaction"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
                abstract="true">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="proxyTargetClass" value="true"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="save*">PROPAGATION_REQUIRED</prop>
                      <prop key="add*">PROPAGATION_REQUIRED</prop>
                      <prop key="update*">PROPAGATION_REQUIRED</prop>
                      <prop key="remove*">PROPAGATION_REQUIRED</prop>
                  </props>
              </property>
          </bean>

    2.     <bean id="userService" parent="baseTransaction">
              <property name="target">
                  <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>
              </property>
          </bean>

      對于上例,則以save,add,update,remove開頭的方法擁有可寫的事務,如果當前有某個方法,如命名為importExcel(),則因沒有transaction而沒有寫權限,這時若方法內有insert,update,delete操作的話,則需要手動設置flush model為Flush.AUTO,如

                                  
      1. session.setFlushMode(FlushMode.AUTO);
      2. session.save(user);
      3. session.flush();

           盡管Open Session In View看起來還不錯,其實副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代碼,這個方法實際上是被父類的doFilter調用的,因此,我們可以大約了解的OpenSessionInViewFilter調用流程: request(請求)->open session并開始transaction->controller->View(Jsp)->結束transaction并close session.

           一切看起來很正確,尤其是在本地開發測試的時候沒出現問題,但試想下如果流程中的某一步被阻塞的話,那在這期間connection就一直被占用而不釋放。最有可能被阻塞的就是在寫Jsp這步,一方面可能是頁面內容大,response.write的時間長,另一方面可能是網速慢,服務器與用戶間傳輸時間久。當大量這樣的情況出現時,就有連接池連接不足,造成頁面假死現象。

      Open Session In View是個雙刃劍,放在公網上內容多流量大的網站請慎用。


      閱讀全文(302) | 回復(0) | 引用通告(638) | 編輯
       

      posted @ 2007-04-03 08:58 lqx 閱讀(241) | 評論 (0)編輯 收藏

      僅列出標題
      共18頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 
      主站蜘蛛池模板: 久久精品中文字幕免费| 特级无码毛片免费视频尤物| 夫妻免费无码V看片| 亚洲成AV人片久久| 69堂人成无码免费视频果冻传媒| 亚洲AV人无码综合在线观看| 国产啪精品视频网站免费尤物| 亚洲色偷拍另类无码专区| 大地资源在线资源免费观看| 久久亚洲综合色一区二区三区| 成全高清在线观看免费| 久久夜色精品国产噜噜噜亚洲AV | 毛片免费视频在线观看| 亚洲一级片在线观看| 成年女人18级毛片毛片免费观看| 香蕉大伊亚洲人在线观看| 四虎www免费人成| 黄色一级毛片免费看| 国产亚洲日韩一区二区三区| 精品视频一区二区三区免费| 久久亚洲sm情趣捆绑调教| 日本XXX黄区免费看| 亚洲最大天堂无码精品区| 五月婷婷亚洲综合| 成人免费一区二区三区| 久久久久亚洲Av无码专| 男男AV纯肉无码免费播放无码 | www.av在线免费观看| 亚洲AV中文无码乱人伦下载| 免费在线视频你懂的| 亚洲av色香蕉一区二区三区 | 久久亚洲精品成人| 韩国免费一级成人毛片| 真正全免费视频a毛片| 久久久久亚洲精品无码系列| 成人性生交大片免费看午夜a| 青青草国产免费国产是公开| 久久久久久亚洲AV无码专区| 日本午夜免费福利视频| 国产成人免费AV在线播放| 亚洲熟伦熟女专区hd高清|