摘要:此的功能是從應(yīng)用程序中隱藏在底層存儲機制中執(zhí)行操作所涉及的所有復(fù)雜性。這正是模式試圖解決的問題。將模式與一起使用開發(fā)人員普遍認為的發(fā)布將模式的功能降級為零,因為該模式只是實體經(jīng)理提供的另一層抽象和復(fù)雜性。在這種情況下,模式有其自己的位置。
案例概述
數(shù)據(jù)訪問對象(DAO)模式是一種結(jié)構(gòu)模式,它允許我們使用抽象API將應(yīng)用程序/業(yè)務(wù)層與持久層(通常是關(guān)系數(shù)據(jù)庫,但它可以是任何其他持久性機制)隔離開來。
此API的功能是從應(yīng)用程序中隱藏在底層存儲機制中執(zhí)行CRUD操作所涉及的所有復(fù)雜性。這允許兩個層分別進化而不知道彼此之間的任何事情。
在本文中,我們將深入研究模式的實現(xiàn),并且我們將學(xué)習(xí)如何使用它來抽象調(diào)用JPA實體管理器。
簡單實施
要了解DAO模式的工作原理,讓我們創(chuàng)建一個基本示例。
假設(shè)我們想要開發(fā)一個管理用戶的應(yīng)用程序。為了使應(yīng)用程序的域模型完全不受數(shù)據(jù)庫的影響,我們將創(chuàng)建一個簡單的DAO類,它將保持這些組件彼此完美地分離。
由于我們的應(yīng)用程序?qū)⑴c用戶一起工作,我們需要定義一個類來實現(xiàn)其模型:
public class User { ????? ????private String name; ????private String email; ????? ????// constructors / standard setters / getters }
User類只是用戶數(shù)據(jù)的普通容器,因此它不實現(xiàn)任何其他值得強調(diào)的行為。
當(dāng)然,我們在這里需要做的最相關(guān)的設(shè)計選擇是如何使使用這個類的應(yīng)用程序與任何可以在某個時候?qū)崿F(xiàn)的持久性機制隔離開來。
這正是DAO模式試圖解決的問題。
DAO API
讓我們定義一個基本的DAO層,這樣我們就可以看到它如何使域模型與持久層完全分離。
這是DAO API:
public interface Dao{ ????? ????Optional get(long id); ????? ????List getAll(); ????? ????void save(T t); ????? ????void update(T t, String[] params); ????? ????void delete(T t); }
從鳥瞰的角度來看,很明顯Dao接口定義了一個抽象API,它對類型為T的對象執(zhí)行CRUD操作。
由于接口提供的抽象級別很高,因此很容易創(chuàng)建與用戶對象一起工作的具體的、細粒度的實現(xiàn)。
UserDao類
讓我們定義Dao接口的特定于用戶的實現(xiàn):
public class UserDao implements Dao{ ????? ????private List users = new ArrayList<>(); ????? ????public UserDao() { ????????users.add(new User("John", "john@domain.com")); ????????users.add(new User("Susan", "susan@domain.com")); ????} ????? ????@Override ????public Optional get(long id) { ????????return Optional.ofNullable(users.get((int) id)); ????} ????? ????@Override ????public List getAll() { ????????return users; ????} ????? ????@Override ????public void save(User user) { ????????users.add(user); ????} ????? ????@Override ????public void update(User user, String[] params) { ????????user.setName(Objects.requireNonNull( ??????????params[0], "Name cannot be null")); ????????user.setEmail(Objects.requireNonNull( ??????????params[1], "Email cannot be null")); ????????? ????????users.add(user); ????} ????? ????@Override ????public void delete(User user) { ????????users.remove(user); ????} }
所述的UserDAO類實現(xiàn)所有用于獲取,更新和刪除所需要的功能的用戶的對象。
為簡單起見,User List的作用類似于內(nèi)存數(shù)據(jù)庫,在構(gòu)造函數(shù)中填充了幾個User對象。
當(dāng)然,重構(gòu)其他方法很容易,因此它們可以用于關(guān)系數(shù)據(jù)庫。
雖然User和UserDao類在同一個應(yīng)用程序中獨立共存,但我們?nèi)匀恍枰纯春笳呷绾斡糜诒3殖志脤訉?yīng)用程序邏輯的隱藏:
public class UserApplication { ? ????private static Dao userDao; ? ????public static void main(String[] args) { ????????userDao = new UserDao(); ????????? ????????User user1 = getUser(0); ????????System.out.println(user1); ????????userDao.update(user1, new String[]{"Jake", "jake@domain.com"}); ????????? ????????User user2 = getUser(1); ????????userDao.delete(user2); ????????userDao.save(new User("Julie", "julie@domain.com")); ????????? ????????userDao.getAll().forEach(user -> System.out.println(user.getName())); ????} ? ????private static User getUser(long id) { ????????Optionaluser = userDao.get(id); ????????? ????????return user.orElseGet( ??????????() -> new User("non-existing user", "no-email")); ????} }
這個例子是人為的,但簡而言之,它顯示了DAO模式背后的動機。在這種情況下,main方法只使用UserDao實例對幾個User對象執(zhí)行CRUD操作。
此過程最相關(guān)的方面是UserDao如何從應(yīng)用程序中隱藏有關(guān)如何持久,更新和刪除對象的所有低級詳細信息。
將模式與JPA一起使用
開發(fā)人員普遍認為JPA的發(fā)布將DAO模式的功能降級為零,因為該模式只是JPA實體經(jīng)理提供的另一層抽象和復(fù)雜性。
毫無疑問,在某些情況下這是事實。即便如此,有時我們只想向我們的應(yīng)用程序公開實體管理器API的一些特定于域的方法。在這種情況下,DAO模式有其自己的位置。
JpaUserDao類
話雖如此,讓我們創(chuàng)建一個Dao接口的新實現(xiàn),這樣我們就可以看到它如何封裝JPA實體管理器提供的開箱即用功能:
public class JpaUserDao implements Dao{ ????? ????private EntityManager entityManager; ????? ????// standard constructors ????? ????@Override ????public Optional get(long id) { ????????return Optional.ofNullable(entityManager.find(User.class, id)); ????} ????? ????@Override ????public List getAll() { ????????Query query = entityManager.createQuery("SELECT e FROM User e"); ????????return query.getResultList(); ????} ????? ????@Override ????public void save(User user) { ????????executeInsideTransaction(entityManager -> entityManager.persist(user)); ????} ????? ????@Override ????public void update(User user, String[] params) { ????????user.setName(Objects.requireNonNull(params[0], "Name cannot be null")); ????????user.setEmail(Objects.requireNonNull(params[1], "Email cannot be null")); ????????executeInsideTransaction(entityManager -> entityManager.merge(user)); ????} ????? ????@Override ????public void delete(User user) { ????????executeInsideTransaction(entityManager -> entityManager.remove(user)); ????} ????? ????private void executeInsideTransaction(Consumer action) { ????????EntityTransaction tx = entityManager.getTransaction(); ????????try { ????????????tx.begin(); ????????????action.accept(entityManager); ????????????tx.commit(); ????????} ????????catch (RuntimeException e) { ????????????tx.rollback(); ????????????throw e; ????????} ????} }
該JpaUserDao類是能夠與由JPA實現(xiàn)所支持的任何關(guān)系數(shù)據(jù)庫的工作。
此外,如果我們仔細研究這個類,我們將會意識到使用Composition和Dependency Injection如何允許我們只調(diào)用應(yīng)用程序所需的實體管理器方法。
簡而言之,我們有一個特定于域的定制API,而不是整個實體管理器的API。
重構(gòu)User類
在這種情況下,我們將使用Hibernate作為JPA默認實現(xiàn),因此我們將相應(yīng)地重構(gòu)User類:
@Entity @Table(name = "users") public class User { ????? ????@Id ????@GeneratedValue(strategy = GenerationType.AUTO) ????private long id; ????? ????private String name; ????private String email; ????? ????// standard constructors / setters / getters }
以編程方式引導(dǎo)JPA實體管理器
假設(shè)我們已經(jīng)在本地或遠程運行MySQL的工作實例,并且數(shù)據(jù)庫表“users”填充了一些用戶記錄,我們需要獲得一個JPA實體管理器,因此我們可以使用JpaUserDao類來執(zhí)行CRUD操作數(shù)據(jù)庫。
在大多數(shù)情況下,我們通過典型的“persistence.xml”文件來實現(xiàn)這一點,這是標準方法。
在這種情況下,我們將采用“xml-less”方法,通過Hibernate方便的EntityManagerFactoryBuilderImpl類獲取具有普通Java的實體管理器。
有關(guān)如何使用Java引導(dǎo)JPA實現(xiàn)的詳細說明,請查看用Java編程引導(dǎo)JPA。
UserApplication類
最后,讓我們重構(gòu)一下初始的UserApplication類,這樣它就可以使用JpaUserDao實例并在User實體上執(zhí)行CRUD操作:
public class UserApplication { ? ????private static DaojpaUserDao; ? ????// standard constructors ????? ????public static void main(String[] args) { ????????User user1 = getUser(1); ????????System.out.println(user1); ????????updateUser(user1, new String[]{"Jake", "jake@domain.com"}); ????????saveUser(new User("Monica", "monica@domain.com")); ????????deleteUser(getUser(2)); ????????getAllUsers().forEach(user -> System.out.println(user.getName())); ????} ????? ????public static User getUser(long id) { ????????Optional user = jpaUserDao.get(id); ????????? ????????return user.orElseGet( ??????????() -> new User("non-existing user", "no-email")); ????} ????? ????public static List getAllUsers() { ????????return jpaUserDao.getAll(); ????} ????? ????public static void updateUser(User user, String[] params) { ????????jpaUserDao.update(user, params); ????} ????? ????public static void saveUser(User user) { ????????jpaUserDao.save(user); ????} ????? ????public static void deleteUser(User user) { ????????jpaUserDao.delete(user); ????} }
即使示例確實非常有限,它仍然有助于演示如何將DAO模式的功能與實體管理器提供的功能集成。
在大多數(shù)應(yīng)用程序中,有一個DI框架,它負責(zé)將JpaUserDao實例注入UserApplication類。為簡單起見,我們省略了此過程的詳細信息。
最相關(guān)的點這里要強調(diào)的是如何在JpaUserDao類有助于保持UserApplication類完全無關(guān)關(guān)于持久層如何執(zhí)行CRUD操作。
此外,由于Dao接口和實體管理器提供的抽象級別,我們可以將MySQL交換到任何其他RDBMS(甚至是平面數(shù)據(jù)庫),而且,我們的應(yīng)用程序仍將按預(yù)期繼續(xù)工作。
案例結(jié)論
在本文中,我們深入研究了DAO模式的關(guān)鍵概念,如何在Java中實現(xiàn)它,以及如何在JPA的實體管理器之上使用它。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73167.html
摘要:適配器模式的結(jié)構(gòu)通過繼承實現(xiàn)通過委讓實現(xiàn)代碼實現(xiàn)目標類使用數(shù)據(jù)線適配類使用轉(zhuǎn)適配線主函數(shù)與在適配器模式中的應(yīng)用當(dāng)前,不少公司使用整合進行系統(tǒng)開發(fā)。 Java 23種設(shè)計模式----適配器模式 1、面向?qū)ο驩O = 面向?qū)ο蠓治鯫OA + 面向?qū)ο笤O(shè)計OOD + 面向?qū)ο缶幊蘋OP 2、編程是一門技術(shù)、同時也是一門藝術(shù) 3、應(yīng)該面向接口編程,而不是面向?qū)崿F(xiàn)編程 什么是設(shè)計模式 設(shè)計模式是...
摘要:何為簡單點來定義就是切面,是一種編程范式。定義一個切面的載體定義一個切點定義一個為,并指定對應(yīng)的切點一個注冊配置類,啟動容器,初始化時期獲取對象,獲取對象時期,并進行打印好了,這樣我們整體的代理就已經(jīng)完成。 問題:Spring AOP代理中的運行時期,是在初始化時期織入還是獲取對象時期織入? 織入就是代理的過程,指目標對象進行封裝轉(zhuǎn)換成代理,實現(xiàn)了代理,就可以運用各種代理的場景模式。 ...
摘要:介紹功能是數(shù)據(jù)操作客戶發(fā)送數(shù)據(jù)到顯示層顯示層發(fā)送數(shù)據(jù)到業(yè)務(wù)層業(yè)務(wù)發(fā)送數(shù)據(jù)到數(shù)據(jù)層數(shù)據(jù)層進行持久化即保存進入一些簡稱業(yè)務(wù)對象的簡稱一個數(shù)據(jù)訪問對象增刪查改數(shù)據(jù)庫一條記錄映射成對象擁有方法為什么使用把的操作進行分離即數(shù)據(jù)庫的操作和業(yè)務(wù)進行分離是 介紹 DAO功能是數(shù)據(jù)操作.客戶發(fā)送數(shù)據(jù)到顯示層,顯示層發(fā)送數(shù)據(jù)到業(yè)務(wù)層,業(yè)務(wù)發(fā)送數(shù)據(jù)到數(shù)據(jù)層,數(shù)據(jù)層進行持久化.即.保存進入databases ...
摘要:顯示層控制層數(shù)據(jù)層統(tǒng)一交給或者處理處理流程客戶端發(fā)送到執(zhí)行讀取返回返回給在返回給在給客戶端問題代碼雜亂即方式客戶端發(fā)送到然后執(zhí)行用于讀取控制器獲取到讀取的數(shù)據(jù)以后再次返回給生成文件給客戶端分為顯示層控制層模型層屬于提供的分布式組件服務(wù)分 Model1 顯示層,控制層,數(shù)據(jù)層,統(tǒng)一交給jsp或者javabean處理. 處理流程 客戶端發(fā)送request 到 jsp jsp 執(zhí)行java...
摘要:在代理類完成以后,最后還需要編寫工廠類,以降低代碼間的耦合度。工廠類工廠類的功能就是直接返回接口的實例化對象這樣客戶端就可以直接通過工廠類取得接口的實例化對象。 數(shù)據(jù) DAO的開發(fā)完全圍繞著數(shù)據(jù)進行,先在數(shù)據(jù)庫中準備幾個要用到的表: sqlcreate table emp ( empno int(4) PRIMARY KEY, ename varchar(10...
閱讀 2044·2023-04-25 15:24
閱讀 1584·2019-08-30 12:55
閱讀 1621·2019-08-29 15:27
閱讀 476·2019-08-26 17:04
閱讀 2412·2019-08-26 10:59
閱讀 1806·2019-08-26 10:44
閱讀 2206·2019-08-22 16:15
閱讀 2594·2019-08-22 15:36