Home >类库下载 >java类库 >Database CRUD operations in Java 8 Streams

Database CRUD operations in Java 8 Streams

高洛峰
高洛峰Original
2016-11-04 09:22:221549browse

When you come into contact with a new tool, the biggest obstacle to overcome at the beginning is how to let yourself try to make a small thing first. Now you may be more confident in your understanding of how the new Stream API works in Java 8, but you may not have used it to perform database queries. To help you get started using the Stream API to create, modify, and read from SQL databases, I've put it all together in this quick-start tutorial. I hope it can help you improve your usage of streaming APIs!

Background

Speedment is an open source tool set that can be used to generate Java entities and manage the communication process with the database. You can use a graphical tool to connect to the database and generate a complete set of ORM framework code to represent the domain model. But Speedment is more than just a code generator, it's a runtime program that can be plugged into your application, making it possible to translate your Java 8 streaming code into optimized SQL queries. This is also a part that I will talk about specifically in this article.

Generate code

To start using Speedment in a Maven project, you need to add the following lines of code to your pom.xml file. In this example, I'm using MySQL, but you can also choose to use PostgreSQL or MariaDB. Proprietary databases like Oracle are available for enterprise customers.

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>

Now you have access to a number of new Maven repositories that make it easier for you to use this toolkit. To start the Speedment UI, execute the following command:

mvn speedment:tool

This will lead you through a process to connect to the database and configure code generation. The easiest way to start is to run it with the default settings first. When you press the Generate button, Speedment will analyze your database metadata and add classes like entities and entity managers to your project.

Initialize Speedment

After your domain model is generated, setting up Speedment is easy. Create a new Main.java file and add the following lines of code. The classes you see are generated, so they are named based on the database schema, table, and column names.

Main.java

ublic class Main {  
public static void main(String... param) {  
final HaresApplication app = new HaresApplicationBuilder()  
.withPassword("password")  
.build();  
}  
}

The above code creates a new application entity using a generated constructor pattern. The constructor makes it possible to set any runtime configuration details, such as the database password.

When we have an application entity, we can use it to access the generated entity manager. Here, I have four tables in my database; “hare”, “carrot”, “human”, and “friend”. (You can find the full database definition here).

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);

Now these entity managers can be used to perform all CRUD operations.

Creating Entities

Creating entities is very straightforward. We just use the implementation of entity generation, set the column value and persist it to the data source. The

hares.persist(  
new HareImpl()  
.setName("Harry")  
.setColor("Gray")  
.setAge(8) 
 );

persist method will return a (potentially) new instance of Hare with auto-generated keys like "id" already set. If we want to continue to use Harry after persistence, we can use this returned by the persist method:

final Hare harry = hares.persist(  
new HareImpl()  
.setName("Harry")  
.setColor("Gray")  
.setAge(8)  
);

If the persistence operation fails, for example, if a foreign key violates a unique constraint, a SpeedmentException will be thrown . We should check this and if there is something implicit that would prevent us from persisting this hare record, we should display an error message.

try {  
final Hare harry = hares.persist(  
new HareImpl()  
.setName("Harry")  
.setColor("Gray")  
.setAge(8)  
);  
} catch (final SpeedmentException ex) {  
System.err.println(ex.getMessage());  
return;  
}

Read Entities

The coolest feature of the Speedment runtime is the ability to use Java 8’s Stream API to stream data in the database. "Why would this be cool?" you might ask yourself. "Even Hibernate supports streaming operations these days!" was the answer.

The best thing about using Speedment streaming operations is that they take into account both the intermediate and terminating actions of building the stream. This means that if you add a filter to the stream after it has been created, the filter will also be taken into account when constructing the SQL statement.

Here is an example where we want to count the total number of hare records in the database.

final long haresTotal = hares.stream().count(); 
System.out.format("There are %d hares in total.%n", haresTotal);

The SQL query that this code will generate is as follows:

SELECT COUNT(id) FROM hares.hare;

The termination operation here is .count(), so Speedment knows to create a SELECT COUNT(...) statement. It also knows that the primary key of the "hare" table is the "id" column, so it is possible to reduce the entire statement sent to the database to this.

A more complex example might be to find the number of rabbits whose names start with "rry" and whose age is 5 or greater. This can be written like this:

final long complexTotal = hares.stream()  .
filter(Hare.NAME.endsWith("rry"))  .
filter(Hare.AGE.greaterOrEqual(5))  .
count();

We define the filter using the located builder generated for us by Speedment. This makes it possible for us to programmatically analyze the stream and reduce it to a SQL statement like this:

SELECT COUNT(id) FROM hares.hare  
WHERE 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上找到。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:java built-in data typesNext article:java built-in data types