背景
Speedment 是一個開放原始碼的工具集,它可以被用來產生 Java 實體,並且能將我們同資料庫的通訊過程管理起來。你可以利用一個圖形工具連接到資料庫並產生一套完整的 ORM 框架程式碼來表示域模型。但是 Speedment 不單單只是一個程式碼產生器而已,它還是一個能插入應用程式中的執行時間程序,這樣就有可能將你的 Java 8 串流程式碼翻譯成優化過的SQL查詢。這也是我將在本文中專門講述的部分。
產生程式碼
要在一個 Maven 工程中開始使用 Speedment,需要你將下面幾行程式碼加入你的 pom.xml 檔案中。在這個例子中,我使用的是 MySQL,而你也可以選擇使用 PostgreSQL 或 MariaDB。針對像Oracle這樣的專有資料庫可用於企業級客戶。
Pom.xml
<properties> <speedment.version>3.0.1</speedment.version> <db.groupId>mysql</db.groupId> <db.artifactId>mysql-connector-java</db.artifactId> <db.version>5.1.39</db.version></properties><dependencies> <dependency> <groupId>com.speedment</groupId> <artifactId>runtime</artifactId> <version>${speedment.version}</version> <type>pom</type> </dependency> <dependency> <groupId>${db.groupId}</groupId> <artifactId>${db.artifactId}</artifactId> <version>${db.version}</version> </dependency></dependencies><build> <plugins> <plugin> <groupId>com.speedment</groupId> <artifactId>speedment-maven-plugin</artifactId> <version>${speedment.version}</version> <dependencies> <dependency> <groupId>${db.groupId}</groupId> <artifactId>${db.artifactId}</artifactId> <version>${db.version}</version> </dependency> </dependencies> </plugin> </plugins></build>
現在你可以存取到許多新的 Maven 資源庫,它們能讓你更輕鬆的使用這個工具包。要啟動 Speedment UI, 執行以下指令:
mvn speedment:tool
這樣就會有一個流程引導你連結到資料庫並對程式碼產生進行設定。一開始最簡單的方法就是用預設的設定先跑起來再說。當你按下產生按鈕「Generate,」 Speedment 就會對你的資料庫元資料進行分析,然後在你的工程中加入像實體和實體管理器這樣的類別。
初始化 Speedment
當你的域模型生成好了以後,Speedment 的設定就容易了。建立一個新的 Main.java 檔案然後新增以下幾行程式碼。你看到的類別都是產生的,因此它們的命名都是根據資料庫模式、表格以及列的名稱來決定的。
Main.java
public class Main { public static void main(String... param) { final HaresApplication app = new HaresApplicationBuilder() .withPassword("password") .build(); } }
上面的程式碼建立了一個新的應用程式實體,它使用了一種產生的建構器模式。構造器是的任何運行時配置細節的設定成為可能,例如資料庫的密碼。
當我們有了一個應用實體,就可以用它來存取產生的實體管理器了。在這裡,我的資料庫中有了四個表; “hare”, “carrot”, “human”, 以及 “friend”. (你可以在這裡找到完整的資料庫定義)。
final CarrotManager carrots = app.getOrThrow(CarrotManager.class);final HareManager hares = app.getOrThrow(HareManager.class);final HumanManager humans = app.getOrThrow(HumanManager.class);final FriendManager hares = app.getOrThrow(FriendManager.class);
現在這些實體管理器可以用來執行所有的CRUD操作了。
創建實體
創建實體的方式非常直接。我們就使用實體產生的實現,把列的值設定好然後持久化到資料來源就可以了。
hares.persist( new HareImpl() .setName("Harry") .setColor("Gray") .setAge(8) );
persist 方法會回傳一個 (潛在的) Hare 新實例,裡面像「id」這種自動產生鍵已經設定好了。如果我們想在持久化之後繼續使用 Harry, 那就可以使用persist 方法返回的這個:
final Hare harry = hares.persist( new HareImpl() .setName("Harry") .setColor("Gray") .setAge(8) );
如果持久化操作失敗了,例如如果有一個外鍵違反了唯一性約束,就會有一個SpeedmentException 拋出。我們應該對此進行檢查,如果有默寫東西會阻止我們對這條 hare 記錄進行持久化,就應該顯示一條錯誤訊息。
try { final Hare harry = hares.persist( new HareImpl() .setName("Harry") .setColor("Gray") .setAge(8) ); } catch (final SpeedmentException ex) { System.err.println(ex.getMessage()); return; }
讀取實體
Speedment 運行時中最酷的功能特性就是能夠使用 Java 8 的 Stream API對資料庫中的資料進行串流操作。 「為什麼這樣做會很酷呢?」 你可能會這樣問你自己。 「如今連Hibernate 都已經支援串流操作了!」這就是答案。
使用 Speedment 流式操作最美好的事情就是它們把構建流的中間和終止動作都考慮進去了。這意味著如果你在流已經被建立之後再增加一個過濾器進去,那麼在建立 SQL 語句時這個過濾器也會被考慮進去。
下面是一個範例,我們想要計算資料庫中 hare 記錄的總數。
final long haresTotal = hares.stream().count();System.out.format("There are %d hares in total.%n", haresTotal);
這段程式碼將會產生的SQL查詢如下:
SELECT COUNT(id) FROM hares.hare;
這裡的終止操作就是 .count() ,因此 Speedment 就知道是要建立一個 SELECT COUNT(…) 語句。它也知道 「hare」表的主鍵是「id」這個列,如此就有可能將發送給資料庫的整個語句 減少到這個樣子。
更複雜的例子可能就是找出名稱以 “rry” 並且年齡大於等於 5 的兔子的數量。這個可以這樣寫:
final long complexTotal = hares.stream() .filter(Hare.NAME.endsWith("rry")) .filter(Hare.AGE.greaterOrEqual(5)) .count();
我們使用由 Speedment 為我們產生的位於建構器來定義過濾器。這使得我們以編程的方式對流進行分析並且將其簡化到如下這樣一條SQL語句成為可能:
SELECT COUNT(id) FROM hares.hareWHERE hare.name LIKE CONCAT("%", ?)AND hare.age >= 5;
如果我們添加了一個Speedment 不可以對流進行優化的操作, 它就會像一般的Java 8 流那被處理。我們永遠不會限制生成的位於建構器的使用,它能是流式操作更加的高效。
final long inefficientTotal = hares.stream() .filter(h -> h.getName().hashCode() == 52) .count();
上述程式碼會產生一個如下極度低效的語句,但是它仍然可以跑起來。
SELECT id,name,color,age FROM hares.hare;
更新實體
更新存在的實體和讀取以及持久化實體非常相似。在我們呼叫update()方法之前,對實體本地拷貝的改變,不會影響資料庫內容。
下面,我們拿到之前使用Hare創建的Harry,並將他的顏色變為棕色:
harry.setColor("brown");final Hare updatedHarry = hares.update(harry);
如果更新被接受了,那么管理器会返回hare的一个新的拷贝,因为我们在后面会继续使用这个实例。就想做“创建”的例子中,更新可能会失败。也许颜色被定义为“值唯一”,棕色已经存在于hare中。那样的话,会抛出一个SpeedmentException异常.
我们也可以通过合并多个实体到一个流中来同时更新他们。加入我们想将所有名字为Harry的hare变为棕色,我们可以这样做:
hares.stream() .filter(Hare.NAME.equal("Harry")) .map(Hare.COLOR.setTo("Brown")) .forEach(hares.updater()); // 更新流中存在的元素
我们还应该使用try-catch语句来确保在运行过程中有失败发生时警告用户。
try { hares.stream() .filter(Hare.NAME.equal("Harry")) .map(Hare.COLOR.setTo("Brown")) .forEach(hares.updater()); } catch (final SpeedmentException ex) { System.err.println(ex.getMessage()); return; }
实体删除
我们需要知道的最后一个 CRUD 操作就是从数据库中删除实体。这个操作几乎和“更新”操作时等同的。假如说我们要把年龄超过10岁的兔子的记录都删除,就要这样做:
try { hares.stream() .filter(Hare.AGE.greaterThan(10)) .forEach(hares.remover()); // Removes remaining hares} catch (final SpeedmentException ex) { System.err.println(ex.getMessage()); return; }
总结
通过阅读本文你已经了解了如何在一个 Maven 工程中对 Speedment 进行设置,还有如何使用 Java 8 的 Stream API 来从数据库中创建、更新、读取以及删除实体。这是你可以利用 Speedment 所能进行的操作的一个小的子集, 但已经是一个能让你上手的好的开始了。更多的示例以及更加高级的使用场景可以在 GitHub-page 上找到。
更多Java 8 Streams 中的数据库 CRUD 操作相关文章请关注PHP中文网!