2017年3月24日 星期五

在不修改原有類的情況下去更改其method

假設已有Dog interface與Hound class
interface Dog{
  void bark();
}

public class Hound implements Dog{
  public void bark(){
     System.out.println("Hound Bark");
  }
}

繼承的方式修改bark()
public class BigHound extends Hound{
   @Override
   public void bark(){
      System.out.println("Big Hound Bark");
   }
}

裝飾者模式修改bark()
public class SmallDog implements Dog{
   private Dog dog;
   public SmallDog(Dog dog) {
       this.dog = dog;
   }

   @Override
   public void bark(){
      System.out.println("Small Dog");
      dog.bark();
   }  
}

動態代理模式
final Dog dog = new Hound();
Dog proxyDog = (Dog)Proxy.newProxyInstance(
                                             dog.getClass().getClassLoader(),
                                             dog.getClass().getInterface(),
                                             new InvocationHandler(){
                                                 public Object invoke(Object proxy, Method method, Object[] args)
                                                            throws Throwable {
                                                     if("run".equals(method.getName())) {
                                                         System.out.println("Proxy Dog");
                                                         return null;
                                                     }
                                                 }
                                             }
);

Transaction( 事務 )

Transaction(事務)的概念:

  • 事務指邏輯上的一組操作,組成這組操作的各單元要就全部成功,要就全部不成功。
  • 資料庫如果沒有自己去控制事務,那預設是一條sql就處於在自己單獨的事物當中。
  • start transaction 為開啟事務,在這條sql語句之後的sql都將處於一個事務中,這些sql語句並不會立即執行
  • commit; 為提交事務,一旦提交,事務中所有的sql才會執行。
  • rollback; 回滾事務,將之前的所有事務取消。
例如:A與B轉帳對應的sql語句
  • update account set money=money-100 where name='A';
  • update account set money=money+100 where name='B';
JDBC中
  • Connection#setAutoCommit(false); // 相當於start transaction
  • Connection#rollback();                     // 相當於rollback
  • Connection#commit();                      // 相當於commit
事務的特性(ACID)
  • 原子性(Atomicity):一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
  • 一致性(Consistency):在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作。
  • 隔離性(Isolation):資料庫允許多個並發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務並發執行時由於交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。
  • 持久性(Durability):事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失。
事務隔離性導致的問題:

  1. 髒讀:當一個事務允許讀取另外一個事務修改但未提交的數據時,就可能發生髒讀。例如,當一個事務A正在讀取資料並且對資料進行了修改,而這種修改還沒提交到資料庫中這時另一個事務B也訪問了這個資料
  2. 不可重複讀:在一次事務中,當一行數據獲取兩遍得到不同的結果表示發生了「不可重複讀」。例如,在一個事務A中多次讀取同一筆資料,在事務A還未結束時,另一個事務B也訪問了這個資料,並且修改這個資料並且commit,那麼事務A在多次讀取這筆資料時可能會讀到不同的資料。
  3. 幻讀:在事務執行過程中,當兩個完全相同的查詢語句執行得到不同的結果集。這種現象稱為「幻讀(phantom read)」。例如:
               目前工資為1000的員工有10人。
                      1.事務A,讀取所有工資為1000的員工。
                        2.這時事務B向employee表插入了一條員工記錄,工資也為1000
                          3.事務B再次讀取所有工資為1000的員工 共讀取到了11條記錄。
        不可重複讀的重點是修改
                        同樣的條件, 你讀取過的數據,再次讀取出來發現值不一樣了
        幻讀的重點在於新增或者刪除
                        同樣的條件, 第 1 次和第 2 次讀出來的記錄數不一

        隔離級別 髒讀 不可重複讀 幻影讀
        未提交讀 可能發生 可能發生 可能發生
        提交讀        - 可能發生 可能發生
        可重複讀        -         - 可能發生
        可序列化         -        -        - 


        2017年3月5日 星期日

        Liskov Substitution principle(里氏替換原則)

        定義:
        1. If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
        2. Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
        簡單的說,就是只要是base class可以使用的地方都能夠使用derived class代替。
        但是反過來就不行了,子類別出現的地方,父類別不一定可以使用。


        2017年3月4日 星期六

        Dependency Inversion Principle(DIP) 依賴倒置

        定義:High level modules should not depend upon low level modules.Both should depend upon
        abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.(高層模組不應該依賴低層模組,這兩層應該依賴於一個抽象。而抽象不一該依賴細節,而是細節去依賴抽象。)

        簡單說就是program to an interface, not an implementation原則。

        在Java中,

        • 抽象:就是interface與abstract class,這兩者都不能直接實體化。
        • 細節:就是指實作那些interface與abstract class的class。
        • 兩層應該依賴於一個抽象:就是指高層的class與低層的class不應該直接互相依賴,它們之間的依賴關係應該要透過interface或是abstract class。
        好處:
        • 比較好測試。因為類與類之間沒有直接依賴而是依賴於interface,因此可以自己建立一個簡單實作該interface的類來測試。
        • 只要符合實作interface,那麼修改下層的實體類,可以不用去動到高層。
        • 在增加低層實體類時,只要去修改高層類,而其他低層的實體類可以不用去修改。

        2017年3月3日 星期五

        Factory method pattern(工廠方法模式)

        定義:Define an interface for creating an object,but let subclasses decide which class to
        instantiate. Factory Method lets a class defer instantiation to subclasses. (為建立的物件定一個介面,但是是讓子類別去決定要讓哪一個類別要實體化,工廠方法讓一個類別的實體化推遲到子類別。)




        Factory method pattern依靠繼承(inheritance),將建立object的工作委託給子類別實作的factory method。

        參與角色(Participants)

        • Product(抽象產品):定義了factory method要建立object的interface,定義這類產品有甚麼方法。
        • ConcreteProduct(具體產品):實作(implement)Product interface。
        • Creator(抽象工廠):宣告factory method,這個method要回傳一個Product type。Creator也可以定義一個預設的factory method,回傳一個預設的ConcreteProduct object。
        • ConcreteCreator(實體工廠):override factory method,實作要回傳哪一種ConcreteProduct instance,包含了實體化object的business logic。
        簡單的Java實作


        好處:
        • 客戶只需要知道如何使用factory method來建立Product object,不需要關心要如何建立。
        • 如果建立這個object很複雜的話,可以將建立的過程隱藏起來。
        • 很容易的增加Product類別,假設要增加一個ProductC,只要實作ProductC,以及ConcreteCreatorC就可以了。
        壞處:
        • 類別數增加,增加系統開銷。

        2017年2月25日 星期六

        N + 1 selects problem

        假設有User,Country,Image等Entity,如下:
        <<Table>>
        IMAGE
        ID <<PK>>
        USERID <<FK>>
        NAME
        TYPE
        DATA
                           
        <<Table>>
        USER
        ID <<PK>>
        COUNTRYID <<FK>>
        USERNAME
                           
        <<Table>>
        COUNTRY
        ID <<PK>>
        NAME
        CAPITAL
        Java Class:
        如果透過以下的方式存取:
        那麼會先產生一個SELECT來load USER entity,
        之後要iterates每個user以取得country,
        因此總共會產生一個(來自query User),再加上N(視你的User總共有多少個)SELECT
        如果已經事先知道一定會取的每個user中的country,那麼這種做法是很沒有效率的。
        另外在Lazily loaded collections也是會發生同樣的問題:

        2017年2月21日 星期二

        開始Hibernate (Bootstrapping Hibernate)

        Persistence:在Java中提到persistence的話,通常是指透過SQL將object instance對應並存放到database中。

        Bootstrapping表示初始化並且開始一個software component

        Hibernate中,分別有JPA BootstrappingNative Bootstrapping(建議使用JPA-standardized bootstrapping)

        JPA Bootstrapping的方式
        JPA的方式中最後目標是要建立javax.persistence.EntityManagerFactory instance
        在JPA標準中定義了兩種bootstrapping,分別是EE,與SE
        • EE bootstrapping,指的是manage and inject the persistence context on behalf of the application.
        • SE bootstrapping,指的是everything else
        而在Hibernate中使用container-bootstrapping 以及 application-bootstrapping兩個術語(term)來表示。

        另外在JPA 2.1 specification中的7.6 7.7有說明使用EntityManager instances的細節。

        Container-bootstrapping中,container會為每個定義在META-INF/persistence.xml configuration file中的persistent-unit建立一個EntityManagerFactory然後讓application能夠透過注入(injection)javax.persistence.PersistenceUnit annotation或是透過JNDI的方式使用。

        Application-bootstrappingapplication要透過 javax.persistence.Persistence 來建立EntityManagerFactory

        可以透過entityManager instance的unwrap()使用provider(也就是Hibernate)API。

        META-INF/persistence.xml檔: 使用EntityManager

        source: https://github.com/readStudy/Hibernate-ORM-Study/tree/master/SetUpHibernateOrm
        Reference: http://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html