Fork me on GitHub

3/14/2014

[MySQL] Multiple foreign key cascade delete

事情是這樣的, 遇到了一個 table B, 他分別 foreign key 到另外兩個 table AC, 我在 B to C 的 foreign key 上面設定了 on delete cascade, 但是我希望 B 因為 C 被刪除也跟著被 cascade delete 的時候, A 也可以一起被刪除.

除了 trigger 之外, 我想不到什麼其他更好的作法, 所以上 stackoverflow 發問一下: http://stackoverflow.com/questions/22341402/mysql-table-multi-foreign-key-cascade, 下面有人提到 DB 的 foreign key 並沒有一對一的限制, 所以希望作到這件事其實有點違背邏輯. 於是乎只好尋求 trigger 一解.

正當我要定義一個 ON DELETE B 的 trigger 去殺掉 A 的時候, 發現由 C cascade delete 驅動 B 刪除, 並不會觸發該 trigger, 上網一查才發現, MySQL 的手冊上寫著 Triggers currently are not activated by foreign key actions.

目前想到的解決方式, 就是原本的 on delete cascade 部份也改成用 trigger...

-- EOF --

1/16/2014

[JPA] Use refresh to get updated data after database trigger

Today I met the issue about EntityManager cache issue.

Let's say that I have 2 tables comment and commant_like. I have a database trigger which increment the field like_count of comment when inserting one new comment_like record.

Below is the orignal code looks like:

In my expectation, the save call will make the database trigger to update the like_count in the comment, but it doesn't.

public void addLikeOnComment(...) {

    commentLikeDao.save(newEntity);
    
    Comment comment = commentDao.find(id);    
    
}

After digging into the code, I found the find has been called somewhere before addLikeComment. so the entity manager will use the cached version message.

public void doWork(...) {

    commentDao.find(id);

    addLikeOnComment(...);

}

The solution is simple. Use the entity manager refresh, to load data from database instead of the cached version

public void addLikeOnComment(...) {

    commentLikeDao.save(newEntity);
    
    Comment comment = commentDao.find(id); 
    commentDao.getEntityManager().refresh(comment)
    
}

-- EOF --

1/09/2014

[Vim] Map Ctrl+S to save file

Beacuse pressing Ctrl-S in terminal will performs an 'XOFF' which stops commands from being receiv

ed. (If Ctrl-S freezes your terminal, type Ctrl-Q to get it going again.)

So, we need to disable that first, put below command in .bashrc

stty stop undef

Then, in the vimrc, add below lines

noremap <silent> <C-S>          :update<CR>
vnoremap <silent> <C-S>         <C-C>:update<CR>
inoremap <silent> <C-S>         <C-O>:update<CR>

It's done. The Ctrl+S has been mapped to :w

References:

  1. In vim how to map “save” to ctrl-s
  2. How to map Ctrl+S in vim on gnome-terminal?

-- EOF --

1/01/2014

[Hibernate] Composite primary key maps composite foreign key

The blog records how to map two entities by the composite keys by using hibernate. Let's say we have 2 entities PrizeItem and PrizeWinnerInfo. We want to map them as OneToOne relation.

The PrizeWinnerInfo (pzwininfo_pzitem_pz_id, pzwininfo_pzitem_id) refer to PrizeItem (pzitem_pz_id, pzitem_id) with the composite foreign key.

Step 0.

Database schema of PrizeItem, table name: ix_prize_item

+----------------------------+--------------+------+-----+---------+-------+
| Field                      | Type         | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+-------+
| pzitem_pz_id               | bigint(20)   | NO   | PRI | NULL    |       |
| pzitem_id                  | int(11)      | NO   | PRI | NULL    |       |
| pzitem_expiration          | datetime     | YES  |     | NULL    |       |
| pzitem_won                 | tinyint(1)   | NO   |     | 0       |       |
| pzitem_won_time            | datetime     | YES  |     | NULL    |       |
| pzitem_winner_info_applied | tinyint(1)   | NO   |     | 0       |       |
| pzitem_pzcha_id            | int(11)      | YES  | MUL | NULL    |       |
| pzitem_serial              | varchar(255) | YES  |     | NULL    |       |
+----------------------------+--------------+------+-----+---------+-------+

Database schema of PrizeWinnerInfo, table name: ix_prize_winner_info

+------------------------+--------------+------+-----+---------+-------+
| Field                  | Type         | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+-------+
| pzwininfo_pzcha_id     | int(11)      | NO   | MUL | 0       |       |
| pzwininfo_pzitem_pz_id | bigint(20)   | NO   | PRI | 0       |       |
| pzwininfo_pzitem_id    | int(11)      | NO   | PRI | 0       |       |
| pzwininfo_name         | varchar(255) | NO   |     | NULL    |       |
| pzwininfo_email        | varchar(128) | NO   |     | NULL    |       |
| pzwininfo_phone        | varchar(32)  | YES  |     | NULL    |       |
| pzwininfo_detail       | longtext     | YES  |     | NULL    |       |
+------------------------+--------------+------+-----+---------+-------+

Step 1.

Tip: Use @Embeddable to define the composite key

The composite primary key PrizeItemPK of PrizeItem

@Embeddable
public class PrizeItemPK implements Serializable
{
    private final static long serialVersionUID = 1L;

    @Column(name="pzitem_pz_id")
    private Long prizeId;

    @Column(name="pzitem_id")
    private Integer prizeItemId;

    public PrizeItemPK() {}
    public PrizeItemPK(Long prizeId, Integer prizeItemId) {
        super();
        this.prizeId = prizeId;
        this.prizeItemId = prizeItemId;
    }

    @JsonGetter("prize_id")
    public Long getPrizeId() {
        return prizeId;
    }

    public void setPrizeId(Long prizeId) {
        this.prizeId = prizeId;
    }

    @JsonGetter("prize_item_id")
    public Integer getPrizeItemId() {
        return prizeItemId;
    }

    public void setPrizeItemId(Integer prizeItemId) {
        this.prizeItemId = prizeItemId;
    }

}

The composite primary key PrizeWinnerInfoPK of PrizeWinnerInfo

@Embeddable
public class PrizeWinnerInfoPK implements Serializable
{
    private final static long serialVersionUID = 1L;

    @Column(name="pzwininfo_pzitem_pz_id")
    private Long prizeId;

    @Column(name="pzwininfo_pzitem_id")
    private Integer prizeItemId;

    public PrizeWinnerInfoPK() {}
    public PrizeWinnerInfoPK(Long prizeId, Integer prizeItemId) {
        super();
        this.prizeId = prizeId;
        this.prizeItemId = prizeItemId;
    }

    @JsonGetter("prize_id")
    public Long getPrizeId() {
        return prizeId;
    }

    public void setPrizeId(Long prizeId) {
        this.prizeId = prizeId;
    }

    @JsonGetter("prize_item_id")
    public Integer getPrizeItemId() {
        return prizeItemId;
    }

    public void setPrizeItemId(Integer prizeItemId) {
        this.prizeItemId = prizeItemId;
    }

}

Step2.

Tip1: Use @OneToMany mapping, not @OneToOne
Tip2: Use @JsonManagedReference and @JsonBackReference to avoid cycling json serialization

ORM entity of PrizeItem

@Entity
@Table(name="ix_prize_item")
@JsonAutoDetect(getterVisibility=JsonAutoDetect.Visibility.NONE)
public class PrizeItem
{
    @EmbeddedId
    private PrizeItemPK pk;

    ...

    @OneToMany(mappedBy="prizeItem", fetch=FetchType.EAGER)
    @JsonBackReference
    private List winnerInfo;

}

ORM entity of PrizeWinnerInfo

@Entity
@Table(name="ix_prize_winner_info")
@JsonAutoDetect(getterVisibility=JsonAutoDetect.Visibility.NONE)
public class PrizeWinnerInfo extends AbstractExtensibleJsonAliasBean
{
    @EmbeddedId
    private PrizeWinnerInfoPK PK;

    ...

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumns ({
        @JoinColumn(name="pzwininfo_pzitem_pz_id", referencedColumnName = "pzitem_pz_id", insertable = false, updatable = false),
        @JoinColumn(name="pzwininfo_pzitem_id", referencedColumnName = "pzitem_id", insertable = false, updatable = false)
    })
    @JsonManagedReference
    private PrizeItem prizeItem;

}

2014/01/16 Note:

I found the use of @JsonBackReference will make the serialization fail on that field. So, I took the below solution (http://stackoverflow.com/a/10111411/474002)

References:

  1. java - hibernate composite Primary key contains a composite foreign key, how to map this - Stack Overflow
  2. java - @OneToOne annotation within composite key class is not working - Stack Overflow
  3. @JoinColumn is part of the composite primary keys | dwuysan

10/17/2013

How the Economic Machine Works


一個蠻通俗易懂的經濟解釋影片, 釐清了不少先前似懂非懂的疑惑, 以下筆記 ...
  • 三個經濟波動的主要的推力:
    1. 生產力成長
    2. 短期 debt cycle
    3. 長期 debt cycle
  • Transaction 是驅動經濟發展的基石, 每個 transaction 都由一個買方跟一個賣方組成, 之間交換 money/credit 來取得貨物, 服務或者其他金融資產
  • Buyer <-> Seller 等同於 Lender <-> Borrower
  • Lender 想由借出的錢賺取更多的錢, Borrower 想要取得更多的錢去得到他所想要的!
  • Lender 付出了 money 取得了 Borrower 的 credit, Borrower 付出了信用換到了錢去買他想要的東西, 但是同時也承擔了未來要償還本金和利息的義務 (debt)
  • 為什麼 credit 很重要, 因為有了 credit 你的花費就允許超過你的收入, 而花費就是驅動經濟的主因!因為一個人的花費就是其他人的收入, 當你有更多的花費代表別人有更多的收入, 有了更多的收入, 銀行就會比較信任然後借錢給你, 也就是你變得比較有 credit
  • increase income -> increase borrowing -> increase spending 不斷循環 (cycles)
  • 在沒有 credit 的時候, 增加 income 的唯一辦法是增加 productivity, 但是可以用 credit 來 borrow 的話, 不需要增加 productivity 也可以增加 income, 進而造成正向循環. 但是如果你用 credit 取得的額外收入拿去做的花費, 不能讓你生產更多的話, 遲早你需要付出代價償還
  • 當市場上的 spending 增加的速度大於 product 生產的速度, 價格就會上漲 -> inflation (通貨膨脹), 中央銀行可以透過調高利率來降低 borrow 的意願, 抑制通貨膨脹. 反過來說, 中央銀行也可以透過降低利率來刺激 borrow 進而刺激 spending
  • short-term debt 就是中央銀行透過調節利率來平衡 credit 的循環. 但儘管如此, 相較於償還 credit, 人類樂觀的天性更傾向於 借多花多以後再說, 所以 short-term debt 仍會慢慢累積越來越多的 debt 超出 income 進而造成 long-term debt
  • 當然, 在 debt 增加但是 income 也對應增加的情況下, 一切仍然是 under control, 這時候就會有一種大家都很有錢的假象. 大家的 income 因為 borrow 都很充裕, 可以拿去投資, 相對的有價資產價格就會飆升, 資產擁有者就覺得自己很有錢. 直到某個時間點, debt 增加的速度高過了 income, 就崩盤了
  • 人們開始 less spending -> less income -> less wealth -> less credit -> less borrowing ->, 這時候降低利率已經沒有用了, 因為重點是收入變少了, 就算借錢是 0 利率也無法幫助還清之前的 debt
  • 面對這種崩盤能有什麼對策:
    1. people, businesses, government cut their spending
    2. debt are reduced through defaults and reconstructings (lender 可以接受償還較少或是以較長的時間償還)
    3. wealth is redistributed
    4. the central bank prints new money
  • 1, 2, 3 都有可能會附帶造成負循環或者不良的社會影響, 而 4 則是刺激正向循環的一個手段. 中央銀行印鈔票去買財務資產, 資產價格上升使得個人的 credit 提昇, 這僅幫助了擁有資產的人. 而中央政府可以付錢買貨物或服務, 那些提供貨物和服務的人可以賺到政府的錢, 但中央政府不能印鈔票. 所以這兩者必須合作. 中央銀行向中央政府購買政府債卷, 即中央銀行借錢給中央政府, 中央政府拿錢取補助失業, 做刺激消費方案(消費卷..等等), 同時也增加了政府的負債. 但是這可以減輕整體 debt
  • 最後給個人的一些建議
    1. Don't have debt rise faster than income
    2. Don't have income rise faster than productivity
    3. Do all that you can to raise your productovity

6/27/2013

HTTP POST and PUT in REST way

HTTP 的 Get/Post/Delete/Put 對應到 Resource 的 CRUD (Create, Retrieve, Update and Delete),其中 POST 和 PUT 最常讓人摸不著頭緒,不知道什麼時候該用什麼。

今天 survey 了一下網路的資料,大概可以歸納出如下兩張圖,未來在遇到相關的設計時可以參照琢磨琢磨。

http-post

http-put

References

  1. SO: PUT vs POST in REST
  2. PUT or POST: The REST of the Story