2010年3月19日 星期五

不要在一個給UIData組件提供數據的函數中訪問數據庫!

不要在一個給UIData組件提供數據的函數中訪問數據庫!例如,我經常看到有人這樣做。這是個壞建議,只會帶來壞的實施。 不要這樣做!

大多數人都沒有意識到(或許他們根本就沒有關注他們使用的ORM工具的 SQL 輸出日誌)在 JSF 生命週期中, 這些表達式不僅僅被計算一次-- 通常多於一次。當每次值表達式提供給UIData組件值的時候, 都會訪問下數據庫。在這之上,根據你獲取的內容和如何實現的方式可能會改變結果集。 On top of that, the result set could change depending on what you are retrieving and how you are doing it.

我將給出一個簡單的示例,然後講解下如何在Seam中解決這個問題。


假設,你使用下面的類來取得一個User實體的數據,UserService 示例用來代理查詢數據庫的操作。
package example;public class UserListBean { private UserService userService; public List getUsers() { return userService.findAll(); }}然後在JSF配置文件中配置該類為managed bean。UserService通過一個EL值表達式註入(或許使用一個ELresolver 從Spring 容器中得到一個示例). 順便提一下,設置該bean的作用域為session是另外一個壞的實踐這裡我不討論這個問題。如果你打算使用Session作用域,建議你去看看Seam的會話作用域。

userList example.UserListBean request userService #{userService}
使用UserListBean類的 getUsers()方法給一個UIData組件提供數據是一個壞的實踐,如下示例:


Name #{user.name}
在這種情況下,當渲染頁面的時候,SQL日誌記錄會顯示多個查詢記錄,假設在該頁面中還有個UICommand組件,在JSF postback節段會有其他的查詢記錄,

正確的做法是,綁定該list到一個上下文變量中,可以使用Seam的工廠組件,這樣不管這個變量沒查詢了多少次,這個用戶的list就會只在每個頁面執行一次。注意下面我們使用了Seam的組件來代替上面的類。使用page 作用域就避免了在JSF postback節段重新查詢數據。

package example;@Name("userList")public class UserListBean { @In private UserService userService; @Factory(value = "users", scope = ScopeType.PAGE) public List getUsers() { return userService.findAll(); }}現在,我們就可以在JSF view中使用這個users 上下文變量了。
Name #{user.name}
請不要再一次進入前面提及的陷阱! 如果你想了解如何把Spring beans注入到你的Seam 組件中,請關注

我最近寫的 Spring into Seam系列的介紹。

From:http://www.mojavelinux.com/blog/archives/2008/05/avoid_this_common_jsf_mistake/

沒有留言:

張貼留言