Minborg

Minborg
Minborg
Showing posts with label Database. Show all posts
Showing posts with label Database. Show all posts

Wednesday, November 27, 2019

Java: How to Create Lightweight Database Microservices

The number of cloud-based Java database applications grows by the minute. Many organizations deploy hundreds if not thousands of microservice instances. However, most applications carry an astounding amount of unnecessary overhead with respect to the runtime environment. This, in turn, makes the application slower and more expensive to run.

In this article, I will demonstrate how to write a database application that is 10 times smaller than normal(*). The storage requirement will be about 32 MB instead of the usual(*) ~300 MB taking both the application, third-party libraries and the Java runtime into account. As a bonus, the required RAM to run the application will also be reduced by 25%.

(*) These are the storage requirements for the following full JDKs (excluding the application and third-party libs):
jdk.8.0_191        360 MB
jdk-9.0.4          504 MB
adoptopenjdk-11    298 MB

Using an ORM that Supports Microservices

Most traditional ORMs do not honor Java module encapsulation. Often, this entails shipping off a lot of unnecessary code.

In this article, I will use the open-source Stream-based Java ORM Speedment, which, in its latest version, supports the Java Platform Module System (JPMS). This enables us to generate an optimized custom Java Runtime Environment (JRE, the parts from the JDK that is needed to run applications) with only the modules explicitly used by our application.

Read about the new features of Speedment 3.2 in this article.

The Application

The entire application we wish to deploy in this article resides as an open-source project on GitHub under the sub-directory “microservice-jlink”. It connects to a public instance of a MySQL “Sakila” database (containing data about films) hosted in the cloud and lists the ten longest films that are rated “PG-13” on the console. The data model is preconfigured to fit the data structure of this database. If you want to create your own application using another database, visit the Speedment initializer to configure a project for that database specifically.

The main method of the application looks like this:

public final class Main {

    public static void main(String[] args) {

        final Speedment app = new SakilaApplicationBuilder()
            .withPassword("sakila")
            .build();

        final FilmManager films = app.getOrThrow(FilmManager.class);

        System.out.println("These are the ten longest films rated as PG-13:");

        films.stream()                          // 1
            .filter(Film.RATING.equal("PG-13")) // 2
            .sorted(Film.LENGTH.reversed())     // 3
            .limit(10)                          // 4
            .map(film -> String.format(         // 5
                "%-18s %d min",
                film.getTitle(),
                film.getLength().orElse(0))
            )
            .forEach(System.out::println);      // 6

    }
}
First, we pass the database password to the Speedment builder (Speedment never stores passwords internally). The builder is pre-configured with the database IP-address, port, etc. from a configuration file.

Then, we obtain the FilmManager which later can be used to create Java Streams that corresponds directly to the “film” table in the database.

At the end, we:
  1. Create a Stream of the Film entities
  2. Filter out Film entities that have a rating equal to “PG-13”
  3. Sorts the remaining films in reversed length order (longest first)
  4. Limits the stream to the first 10 films
  5. Maps each film entity to a String with film title and film length
  6. Prints each String to the console

The application itself is very easy to understand. It shall also be noted that Speedment will render the Java Stream to SQL under the hood as shown hereunder:
SELECT 
    `film_id`,`title`,`description`,`release_year`,
    `language_id`,`original_language_id`,`rental_duration`,`rental_rate`,
    `length`,`replacement_cost`,`rating`,`special_features`,`last_update`
FROM `sakila`.`film` 
WHERE (`rating` = ? COLLATE utf8_bin) 
ORDER BY `length`IS NOT NULL, `length` DESC LIMIT ?,
values:[PG-13, 10]

This means that only the desired film entities are ever pulled in from the database.

When running directly under the IDE, the following output is produced:

These are the ten longest films rated as PG-13:
GANGS PRIDE        185 min
CHICAGO NORTH      185 min
POND SEATTLE       185 min
THEORY MERMAID     184 min
CONSPIRACY SPIRIT  184 min
FRONTIER CABIN     183 min
REDS POCUS         182 min
HOTEL HAPPINESS    181 min
JACKET FRISCO      181 min
MIXED DOORS        180 min

This looks perfect.

Modularizing the Project

To use modules, we need to run under Java 9 or greater and there has to be a module-info.java file in our project:

module microservice.jlink {
    requires com.speedment.runtime.application;
    requires com.speedment.runtime.connector.mysql; // (*)
}
The module com.speedment.runtime.application is the basic module that is always needed by any Speedment application.

(*) Depending on the database type, you have to replace the MySQL module with the corresponding module for your database. Read all about the various database connector modules here.

Building the Project

As mentioned earlier, the complete project is available on GitHub. This is how you get it:

git clone https://github.com/speedment/user-guide-code-samples.git

Change directory to the relevant sub-project:
cd user-guide-code-samples
cd microservice-jlink

Build the project (you must use Java 9 or higher because of the module system):

mvn clean install

A Custom JRE Build Script

The project also contains a custom JRE build script called build_jre.sh containing the following commands:

#!/bin/bash
SPEEDMENT_VERSION=3.2.1
JDBC_VERSION=8.0.18
OUTPUT=customjre
echo "Building $OUTPUT..."
MODULEPATH=$(find ~/.m2/repository/com/speedment/runtime -name "*.jar" \
  | grep $SPEEDMENT_VERSION.jar | xargs echo | tr ' ' ':')
MODULEPATH=$MODULEPATH:$(find ~/.m2/repository/com/speedment/common -name "*.jar" \
  | grep $SPEEDMENT_VERSION.jar | xargs echo | tr ' ' ':')
MODULEPATH=$MODULEPATH:$(find . -name "*.jar" | xargs echo | tr ' ' ':')

$JAVA_HOME/bin/jlink \
--no-header-files \
--no-man-pages \
--compress=2 \
--strip-debug \
--module-path "$JAVA_HOME\jmods:$MODULEPATH" \
--add-modules microservice.jlink,java.management,java.naming,java.rmi,java.transaction.xa \
--output $OUTPUT

This is how the script works:

After setting various parameters, the script builds up the module path by adding the jars of the speedment/runtime and speedment/common directories. Even though we are adding all of them, the module system will later figure out which ones are actually used and discard the other ones. The last line with MODULEPATH will add the JAR file of the application itself.

After all the parameters have been set, we invoke the jlink command which will build the custom JRE. I have used a number of (optional) flags to reduce the size of the target JRE. Because the JDBC driver does not support JPMS, I have manually added some modules that are needed by the driver under the --add-modules parameter.

Building the Ultra-Compact JRE

Armed with the script above, we can create the ultra-compact custom JRE for our cloud database application with a single command:

./build_jre.sh
The build only takes about 5 seconds on my older MacBook Pro. We can check out the total size of the JRE/app with this command:

du -sh customjre/

This will produce the following output:
 32M customjre/
A staggering result! We have a full-fledged JVM with garbage collect, JIT compiler, all libraries (except the JDBC driver) and the application itself packed into only 32 MB of storage!

We can compare this to the JDK itself in its unreduced size which is often used as a baseline for cloud instances.
du -sh $JAVA_HOME

This will produce the following output on my laptop:

298M /Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home/

And this figure does not even include the application or any third-party libraries. So, we have reduced the storage requirements with a factor of perhaps 10!

Modules Actually Used

To see what modules that made it through the reduction process, we can issue the following command:
cat customjre/release

This will produce the following output on my machine (reformatted and sorted for clarity):
JAVA_VERSION="11.0.5"
MODULES="
com.speedment.common.annotation
com.speedment.common.function
com.speedment.common.injector
com.speedment.common.invariant
com.speedment.common.json
com.speedment.common.jvm_version
com.speedment.common.logger
com.speedment.common.mapstream
com.speedment.common.tuple
com.speedment.runtime.application
com.speedment.runtime.compute
com.speedment.runtime.config
com.speedment.runtime.connector.mysql
com.speedment.runtime.core
com.speedment.runtime.field
com.speedment.runtime.typemapper
com.speedment.runtime.welcome
java.base
java.logging
java.management
java.naming
java.prefs
java.rmi
java.security.sasl
java.sql
java.transaction.xa
java.xml
microservice.jlink
"

So, all of Java's modules that were unused (such as javax.crypto) were not included in the custom runtime.

Running the Application

The application can be run using the custom JRE like this:
customjre/bin/java --class-path ~/.m2/repository/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar -m microservice.jlink/com.speedment.example.microservices.jlink.Main

The file mysql-connector-java-8.0.18.jar was automatically downloaded by Maven to its local repository when the project was first built (i.e. mvn clean install). Because the MySQL JDBC driver is not compatible with the Java Platform Module System yet, we had to glue it on manually.

When run, the program produces the same output as it did above but from a runtime that was 10 times smaller:
These are the ten longest films rated as PG-13:
GANGS PRIDE        185 min
CHICAGO NORTH      185 min
POND SEATTLE       185 min
THEORY MERMAID     184 min
CONSPIRACY SPIRIT  184 min
FRONTIER CABIN     183 min
REDS POCUS         182 min
HOTEL HAPPINESS    181 min
JACKET FRISCO      181 min
MIXED DOORS        180 min

Memory Usage

A perhaps more important issue is how much application memory (RSS) that is being used by the cloud application in total. A quick look at this reveals that the heap memory usage is also reduced:

Standard JDK

Pers-MBP:speedment pemi$  jmap -histo 38715
 num     #instances         #bytes  class name (module)
-------------------------------------------------------
   1:         25836        3036560  [B (java.base@11.0.5)
   2:          2055        1639408  [I (java.base@11.0.5)
   3:          4234         511568  java.lang.Class (java.base@11.0.5)
   4:         21233         509592  java.lang.String (java.base@11.0.5)
   5:           196         270552  [C (java.base@11.0.5)
   6:          4181         245400  [Ljava.lang.Object; (java.base@11.0.5)
   7:          4801         153632  java.util.concurrent.ConcurrentHashMap$Node (java.base@11.0.5)
   8:          3395         135800  java.util.LinkedHashMap$Entry (java.base@11.0.5)
…
1804:             1             16  sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo (jdk.localedata@11.0.5)
Total        137524        7800144

Custom JRE

Pers-MBP:speedment pemi$  jmap -histo 38783 | head
 num     #instances         #bytes  class name (module)
-------------------------------------------------------
   1:         22323        1714608  [B (java.base@11.0.5)
   2:          4229         511000  java.lang.Class (java.base@11.0.5)
   3:         19447         466728  java.lang.String (java.base@11.0.5)
   4:          1776         424408  [I (java.base@11.0.5)
   5:            69         264656  [C (java.base@11.0.5)
   6:          4044         240128  [Ljava.lang.Object; (java.base@11.0.5)
   7:          4665         149280  java.util.concurrent.ConcurrentHashMap$Node (java.base@11.0.5)
   8:          3395         135800  java.util.LinkedHashMap$Entry (java.base@11.0.5)
…
1726:             1             16  sun.util.resources.LocaleData$LocaleDataStrategy (java.base@11.0.5)
Total        102904        5727960

Heap Improvement

The heap usage was reduced from 7,800,144 to 5,727,960 bytes (a reduction of over 25%)!

NB: Before I ran the jmap command, I let the application suggest an explicit Garbage Collect and wait for some seconds to even out any differences caused by potential earlier invocations of the Garbage Collector.

Overview

Here is a chart that shows the difference in storage requirements (lower is better):


Here is another chart that shows the difference in RAM usage (lower is better):


Modifying the Code

If you want to modify the code, you need to rebuild the app after your changes with:
mvn clean install

and then remove the old customjre and create a new one:
rm -rf customjre/
./build_jre.sh 

Creating Your own Database Application

If you want to connect to your own database and want to write your own application logic, you can easily select what tables and columns you want to use and then generate your own java domain model and application builder automatically using the Speedment Tool:

The Speedment tool as used in the project demonstrated in this article.

The tool can be added to your project in the pom.xml file and invoked by mvn speedment:tool. Visit the Speedment Initializer to generate your own custom pom.xml file and application template.

The process can be streamlined by automatic Maven build scripts that will identify any application dependencies and automatic generation of Docker instances that can be deployed instantly following an automatic build. I will write more about this in the coming articles.

Conclusions

The Java Platform Module System (JPMS) allows the building of highly optimized JREs suitable for cloud deployment.
It is possible to reduce both storage and RAM requirements.
Traditional ORMs do not honor full Java module encapsulation
Speedment open-source Stream ORM supports JPMS and can be used to build highly efficient database cloud applications.

Resources

Basics about JPMS modules
Speedment on GitHub
The Speedment Initializer capable of generating project pom.xml templates

Monday, October 24, 2016

Work with Parallel Database Streams using Java 8

What is a Parallel Database Stream?

Read this post and learn how you can process data from a database in parallel using parallel streams and Speedment. Parallel streams can, under many circumstances, be significantly faster than the usual sequential streams.

With the introduction of Java 8, we got the long awaited Stream library. One of the advantages with streams is that it is very easy to make streams parallel. Basically, we could take any stream and then just apply the method parallel() and we get a parallel stream instead of a sequential one. By default, parallel streams are executed by the common ForkJoinPool.
Spire and Duke Working in Parallel

Parallel streams are good if the work items to be performed in the parallel stream pipelines are largely uncoupled and when the effort of dividing up the work in several threads is relatively low. Equally, the effort of combining the parallel results must also be relatively low.

So, if we have work items that are relatively compute intensive, then parallel streams would often make sense.

Speedment is an open-source Stream ORM Java Toolkit and RuntimeJava tool that wraps an existing database and its tables into Java 8 streams. We can use an existing database and run the Speedment tool and it will generate POJO classes that corresponds to the tables we have selected using the tool.

One cool feature with Speedment is that the database streams supports parallelism using the standard Stream semantics. This way, we can easily work with database content in parallel and produce results much faster than if we process the streams sequentially!

Getting Started With Speedment

Visit open-souce Speedment on GitHub and learn how to get started with a Speedment project. It should be very easy to connect the tool to an existing database.

In this post, the following MySQL table is used for the examples below.

CREATE TABLE `prime_candidate` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` bigint(20) NOT NULL,
  `prime` bit(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;


The idea is that people may insert values into this table and then we will write an application that computes if the inserted values are a prime numbers or not. In a real case scenario, we could use any table in a MySQL, PostgreSQL or MariaDB database.

Writing a Sequential Stream Solution

First, we need to have a method that returns if a value is a prime number. Here is a simple way of doing it. Note that the algorithm is purposely made slow so we clearly can se the effects of parallel streams over an expensive operation.

public class PrimeUtil {

    /**
     * Returns if the given parameter is a prime number.
     *
     * @param n the given prime number candidate
     * @return if the given parameter is a prime number
     */
        static boolean isPrime(long n) {
        // primes are equal or greater than 2 
        if (n < 2) {
            return false;
        }
        // check if n is even
        if (n % 2 == 0) {
            // 2 is the only even prime
            // all other even n:s are not
            return n == 2;
        }
        // if odd, then just check the odds
        // up to the square root of n
        // for (int i = 3; i * i <= n; i += 2) {
        //
        // Make the methods purposely slow by
        // checking all the way up to n
        for (int i = 3; i <= n; i += 2) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }

}

Again, the object of this post is not to devise an efficient prime number determination method.

Given this simple prime number method, we can now easily write a Speedment application that will scan the database table for undetermined prime number candidates and then it will determine if they are primes or not and update the table accordingly. This is how it might look:

final JavapotApplication app = new JavapotApplicationBuilder()
            .withPassword("javapot") // Replace with the real password
            .withLogging(LogType.STREAM)
            .build();
        
        final Manager<PrimeCandidate> candidates = app.getOrThrow(PrimeCandidateManager.class);
        
        candidates.stream()
            .filter(PrimeCandidate.PRIME.isNull())                      // Filter out undetermined primes
            .map(pc -> pc.setPrime(PrimeUtil.isPrime(pc.getValue())))   // Sets if it is a prime or not
            .forEach(candidates.updater());                             // Applies the Manager's updater

The last part contains the interesting stuff. First, we create a stream over all candidates where the 'prime' column is null using the stream().filter(PrimeCandidate.PRIME.isNull()) method. It is important to understand that the Speedment stream implementation will recognize the filter predicate and will be able to use that to reduce the number of candidates that are actually pulled in from the database (e.g. a "SELECT * FROM candidate WHERE prime IS NULL" will be used). Then, for each such prime candidate pc, we either set the 'prime' column to true if pc.getValue() is a prime or false if pc.getValue() is not a prime. Interestingly, the pc.setPrime() method returns the entity pc itself, allowing us to easily tag on multiple stream operations. On the last line, we update the database with the result of our check by applying the candidates.updater() function. So, this application's main functionality is really a one-liner (broken up into five lines for improved readability).

Now, before we can test our application, we need to generate some test data input. Here is an example of how that can be done using Speedment:

final JavapotApplication app = new JavapotApplicationBuilder()
            .withPassword("javapot") // Replace with the real password
            .build();

        final Manager<PrimeCandidate> candidates = app.getOrThrow(PrimeCandidateManager.class);

        final Random random = new SecureRandom();

        // Create a bunch of new prime candidates
        random.longs(1_100, 0, Integer.MAX_VALUE)
            .mapToObj(new PrimeCandidateImpl()::setValue)  // Sets the random value 
            .forEach(candidates.persister());              // Applies the Manager's persister function

Again, we can accomplish our task with just a few lines of code.

Try the Default Parallel Stream

If we want to parallelize our stream, we just need to add one single method to our previous solution:

        candidates.stream()
            .parallel()                                 // Now indicates a parallel stream
            .filter(PrimeCandidate.PRIME.isNull())
            .map(pc -> pc.setPrime(PrimeUtil.isPrime(pc.getValue())))
            .forEach(candidates.updater());             // Applies the Manager's updater

And we are parallel! However, by default, Speedment is using Java's default parallelization behavior (as defined in Spliterators::spliteratorUnknownSize) which is optimized for non-compute-intensive operations. If we analyze Java's default parallelization behavior, we will determine that it will use a first thread for the first 1024 work items, a second thread for the following 2*1024 = 2048 work items and then 3*1024 = 3072 work items for the third thread and so on. This is bad for our application, where the cost of each operation is very high. If we are computing 1100 prime candidates, we will only use two threads because the first thread will take on the first 1024 items and the second thread will take on the rest 76. Modern servers have a lot more threads than that. Read the next section to see how we can fix this issue.

Built-in Parallelization Strategies

Speedment has a number of built-in parallelization strategies that we can select depending on the work item's expected computational demands. This is an improvement over Java 8 that only has one default strategy. The built-in parallel strategies are:

@FunctionalInterface
public interface ParallelStrategy {

    /**
     * A Parallel Strategy that is Java's default <code>Iterator</code> to
     * <code>Spliterator</code> converter. It favors relatively large sets (in
     * the ten thousands or more) with low computational overhead.
     *
     * @return a ParallelStrategy
     */
    static ParallelStrategy computeIntensityDefault() {...}

    /**
     * A Parallel Strategy that favors relatively small to medium sets with
     * medium computational overhead.
     *
     * @return a ParallelStrategy
     */
    static ParallelStrategy computeIntensityMedium() {...}

    /**
     * A Parallel Strategy that favors relatively small to medium sets with high
     * computational overhead.
     *
     * @return a ParallelStrategy
     */
    static ParallelStrategy computeIntensityHigh() {...}

    /**
     * A Parallel Strategy that favors small sets with extremely high
     * computational overhead. The set will be split up in solitary elements
     * that are executed separately in their own thread.
     *
     * @return a ParallelStrategy
     */
    static ParallelStrategy computeIntensityExtreme() {...}

    <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics);

    static ParallelStrategy of(final int... batchSizes) {
        return new ParallelStrategy() {
            @Override
            public <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics) {
                return ConfigurableIteratorSpliterator.of(iterator, characteristics, batchSizes);
            }
        };
    }

Applying a Parallel Strategy

The only thing we have to do is to configure a parallelization strategy to a manager like this, and we are good to go:

Manager<PrimeCandidate> candidatesHigh = app.configure(PrimeCandidateManager.class)
            .withParallelStrategy(ParallelStrategy.computeIntensityHigh())
            .build();

        candidatesHigh.stream() // Better parallel performance for our case!
            .parallel()
            .filter(PrimeCandidate.PRIME.isNull())
            .map(pc -> pc.setPrime(PrimeUtil.isPrime(pc.getValue())))
            .forEach(candidatesHigh.updater());

The ParallelStrategy.computeIntensityHigh() strategy will break up the work items in much smaller chunks. This will give us considerably better performance, since we now are going to use all the available threads. If we look under the hood, we can see that the strategy is defined like this:

    private final static int[] BATCH_SIZES = IntStream.range(0, 8)
            .map(ComputeIntensityUtil::toThePowerOfTwo)
            .flatMap(ComputeIntensityUtil::repeatOnHalfAvailableProcessors)
            .toArray();


This means that, on a computer with 8 threads, it will put one item on thread 1-4, two items on thread 5-8 and when the tasks are completed there will be four items on the next four available threads, then eight items and so on until we reach 256 which is the maximum items put on any thread. Obviously, this strategy is much better than Java's standard strategy for this particular problem.

Here is how the threads in the common ForkJoinPool looks like on my 8 threaded laptop:


Create Your Own Parallel Strategy

One cool thing with Speedment is that we, very easily, can write our parallelization strategy and just inject it into our streams. Consider this custom parallelization strategy:

    public static class MyParallelStrategy implements ParallelStrategy {

        private final static int[] BATCH_SIZES = {1, 2, 4, 8};

        @Override
        public <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics) {
            return ConfigurableIteratorSpliterator.of(iterator, characteristics, BATCH_SIZES);
        }

    }

Which, in fact, it can be expressed even shorter:

    ParallelStrategy myParallelStrategy = ParallelStrategy.of(1, 2, 4, 8);


This strategy will put one work item on the first available thread, two on the second, four on the third, eight on the fourth with eight being the last digit in our array. The last digit will then be used for all subsequent available threads. So the order really becomes 1, 2, 4, 8, 8, 8, 8, ... We can now use our new strategy as follows:

Manager<PrimeCandidate> candidatesCustom = app.configure(PrimeCandidateManager.class)
            .withParallelStrategy(myParallelStrategy)
            .build();

        candidatesCustom.stream()
            .parallel()
            .filter(PrimeCandidate.PRIME.isNull())
            .map(pc -> pc.setPrime(PrimeUtil.isPrime(pc.getValue())))
            .forEach(candidatesCustom.updater());

Voilà! We have full control over how the work items are laid out over the available execution threads.

Benchmarks

All benchmarks used the same input of prime candidates. Tests were run on a MacBook Pro, 2.2 GHz Intel Core i7 with 4 physical cores and 8 threads.

Strategy

Sequential                       265 s (One thread processed all 1100 items)
Parallel Default Java 8          235 s (Because 1024 items were processed by thread 1 and 76 items by thread 2)
Parallel computeIntensityHigh()   69 s (All 4 hardware cores were used)

Conclusions

Speedment supports parallel processing of database content.

Speedment supports a variety of parallel strategies to allow full utilization of the execution environment.

We can easily create our own parallel strategies and use them in our Speedment streams.

It is possible to improve performance significantly by carefully selecting a parallel strategy over just settling with Java's default one.

Thursday, November 12, 2015

Easily Create Database Content with Java 8

Database Connectivity Now and Then

Spire and Duke adding stuff
to a database.
I remember back in the old (Java) days, when we were sitting up late nights and experimented a lot with Java and databases. In the beginning of the Java era, there was not much support for database connectivity and so we had to basically write your own database classes and handle ResultSets, Connections and SQLExceptions by ourself.

Nowadays, we expect the simple things just to happen! Suppose that we have an existing database and we want to add or update information in it using a Java application. How can we do that in a simple way without having to write a lot of boilerplate code?

I have contributed a lot to the Java 8 Open Source project Speedment, that can be used to very easily extract Java code from existing database schemas and start coding applications directly.

Let's take it for a spin.

Example

Let's say we have a MySQL database table that is supposed to contain data on various countries. The table could look something like this:

mysql> explain country +------------+-------------+------+-----+---------+----------------+ | Field      | Type        | Null | Key | Default | Extra          | +------------+-------------+------+-----+---------+----------------+ | id         | int(11)     | NO   | PRI | NULL    | auto_increment | | name       | varchar(45) | YES  | UNI | NULL    |                | | local_name | varchar(45) | YES  |     | NULL    |                | | code       | int(11)     | YES  |     | NULL    |                | | domain     | varchar(10) | YES  |     | NULL    |                +------------+-------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)

Let us further pretend that we have the task of populating the table with a few countries and see how that can be solved.

Setting up the Speedment Project

In order to set up a project with Speedment, we need to include a few lines in our POM.xml file, connect to the database and generate code. Read more on how to do this here!.

Also, check out this film how easy it is:

Initializing the Database Connection

Now that we have our database domain model generated automatically, we can start with the actual coding for inserting data into the database. First, we need to setup our Java 8 database project like this:

// Setup Speedment speedment = new JavapotApplication().withPassword("javapot").build(); Manager<Country> countries = speedment.managerOf(Country.class);

The JavapotApplication class was generated automatically from the database schema and contains all meta data (like columns and tables) of the database. Note that we manually need to provide the password since this is not stored in the meta data model (for security reasons). The countries variable is a "handle" for the table we are about to work with.

There is really no "magic" going on with the generation. We can see all the generated Java files in clear text and we can change them or introduce our own versions if we want.

Inserting Data in the Database

Once the setup is made, is is very easy to insert data rows in the database like this:

try { countries.newInstance() .setName("United States") .setLocalName("United States") .setCode(1) .setDomain(".us") .persist(); countries.newInstance() .setName("Germany") .setLocalName("Deutschland") .setCode(49) .setDomain(".de") .persist(); // Needless to say, you can call the setters in any order. countries.newInstance() .setDomain(".uk") .setCode(44) .setName("United Kingdom") .setLocalName("United Kingdom") .setDomain(".uk") .persist(); countries.newInstance() .setName("Sweden") .setLocalName("Sverige") .setCode(40) // Intentionally wrong, should be 46!! .setDomain(".se") .persist(); } catch (SpeedmentException se) { // Handle the exception here }

The newInstance() method creates a new empty Country object and then we just use the setters to initialize the country. After all parameters are set, we call the persist() method to store the object in the database. If there is an error during the database insert, a SpeedmentException will be thrown, allowing you to examine why (for example if you are trying to insert two countries with the same name).  I intentionally picked the wrong country call code for Sweden (förlåt Sverige) so that we can learn how to update data in our database too.

Updating Data in the Database

If you want to update an existing row in the database you can do it like this:

countries.stream() .filter(Country.NAME.equal("Sweden")) .findAny() .ifPresent(c -> c.setCode(46).update());

This will create a Stream with all the counties that have the name "Sweden" (which, evidently, is only one country) and then it will try to find that country and if it is present, it will take that country and set the code to 46 (which is the correct calling code for Sweden) and then it will update the selected country in the database. It is important to understand that even though our country table might contain a large number of countries, it will only include those countries in the stream that are satisfying an equivalent query of "select * from country where name='Sweden' " in this case.

Now our database looks like this:
mysql> select * from country; +----+----------------+----------------+------+--------+ | id | name           | local_name     | code | domain | +----+----------------+----------------+------+--------+ |  1 | United States  | United States  |    1 | .us    | |  2 | Germany        | Deutschland    |   49 | .de    | |  3 | United Kingdom | United Kingdom |   44 | .uk    | |  4 | Sweden         | Sverige       |   46 | .se    | +----+----------------+----------------+------+--------+ 4 rows in set (0.00 sec)

Success! Mission accomplished!

Contributing 

Read more about Speedment Open Source on www.speedment.org and that's the place to be if you want to learn more things like how the API looks like and how you use Speedment in your projects. Speedment is here on GitHub. You can contribute by submitting comments on gitter or download the source code and create pull requests with your own code contributions.

Conclusions

With Java 8, you can easily write database applications with almost no extra manual code work. There are tools that automatically can extract your domain model from a database schema.

These days, we Java programmers can can put more time on the actual problem (and perhaps get some more well deserved sleep) instead of fiddling around with basic database functionality.