Mystral (pronounced "Mistral") is an efficient library to deal with relational databases quickly.

Overview

Mystral

An efficient library to deal with relational databases quickly.

A little request: read the Javadoc to understand how these elements work in deep.

Prerequisites

This library requires Java 8.
Before reading on, make sure the DBMS' drivers you are using are correctly loaded. If you are working under Spigot API, MySQL drivers will be already loaded.

Maven artifacts

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>com.github.glyart</groupId>
        <artifactId>mystral</artifactId>
        <version>1.2.1-SNAPSHOT</version>
    </dependency>
</dependencies>

Why Mystral?

Mystral merges Spring JDBC's user-friendliness and HikariCP's speed (along with its connection pooling system).

This library helps to avoid writing boilerplate code which is common for developers dealing with JDBC.

Note: this library follows the same logic as Spring JDBC. We simplified it and only took the very essentials elements for projects which don't need an entire framework support.
Learn more about Spring JDBC.
Learn more about JDBC.

Also, Mystral supports asynchronous computation. Read more about this in the following sections.

Getting started

Just start by instantiating a Credentials object.

Credentials credentials = Credentials.builder()
  .host("yourHostName")
  .password("yourPassword")
  .user("yourUsername")
  .schema("yourDatabase")
  .pool("yourPoolName")
  //.port(3306) you can avoid specifying the port (default is 3306)
  .build();

Working Asynchronously

If you are working synchronously, you can skip this section.

Implementing Executor

In order to work, the AsyncDatabase class needs an implementation of the Executor interface. Internally, each data access operation is a task, implemented via Runnable tasks.
Such tasks are executed by your Executor implementation.

A very simple implementation:

Executor exe = (command) -> new Thread(command).start();

If the environment you are working with has strictly rules for async computation, then you may need to use its scheduler.

For example:

Executor exe = YourEnvironmentScheduler::schedule;

Here are some examples if you are working with Minecraft plugin-related projects.

Spigot:

Executor exe = (command) -> Bukkit.getScheduler().runTaskAsynchronously(plugin, command);

Bungeecord:

Executor exe = (command) -> getProxy().getScheduler().runAsync(plugin, command);

Velocity:

Executor exe = (command) -> yourProxyServer.getScheduler().buildTask(plugin, command).schedule();

If you are using Sponge, you can get a ready-to-use Executor service called SpongeExecutorService:

SpongeExecutorService exe = Sponge.getScheduler().createAsyncExecutor(plugin);

Read more about task scheduling on Sponge.

Instantiating AsyncDatabase

Finally, we are ready to use the AsyncDatabase class to access the database. You can get its instance by doing:

AsyncDatabase asyncDb = Mystral.newAsyncDatabase(credentials, exe);

The AsyncDatabase class has a lot of methods, which can perform data access operations given callback objects. Anyway, you don't need to do such complicated things: these methods are heavily overloaded. Each overload gives different combination of parameters, until we get methods which don't need callback objects, because default callback implementations are already provided internally.

Remember that every data access method returns a CompletableFuture object. You must invoke the whenComplete method when accessing the result(s), which could be null.

Working synchronously

If you need to work synchronously, just use the Database class.

Database db = Mystral.newDatabase(credentials);

This class' usage is almost as similar as its asynchronous counterpart. The main differences are listed in the table below.


Differences between usages
Sync Async
What does it returns? The raw result. It could be null. A never null CompletableFuture object which wraps the result (it could be null).
How do I handle exceptions? Exceptions in sync usage are unchecked. You don't have to use a try-catch block if it isn't needed. You can handle exceptions inside the whenComplete method.
Who carries out the operations? The thread where methods are called from. The Executor implementation.

Usage

Note: the following examples will deal with asynchronous usage.

Let's assume we are working with a simple table:

https://i.imgur.com/AFatpsY.png

We need to represent tables by using Java classes, but this is simple either:

public class User {

    private int id;
    private String name;
    private int score;

    public User(int id, String name) {
        this.id = id;
        this.name = name;	
    }

    // getters, setter, constructor(s)
}

This section will only show examples on methods whose parameters take:

  • SQL statements (static or with "?" placeholders);
  • Array of objects representing the SQL statement's parameters (needed with parametrized SQL statements only) and array of Types representing parameters' types;
  • Lambda functions (ResultSetRowMapper) which hold a mapping logic for supplying results (query methods only);
  • Two other interfaces used for batch updates. They will be discussed in the batch updates section.

Query

If you need to query the database you can use two methods: queryForList and queryForObject.

The first one gets a list of results, the second one gets one result. Use it when you are sure that the query will supply exactly one result.

Query methods need a ResultSetRowMapper implementation. A ResultSetRowMapper implementation maps a result for each ResultSet row (we don't worry about exceptions or empty ResultSets).

Example on getting a list by using a static SQL statement:

CompletableFuture<List<User>> future = asyncDb.queryForList("SELECT * FROM users", (resultSet, rowNumber) -> {
    /* We use this ResultSetRowMapper implementation to work with ResultSet's rows.
    *  For example, if we want to get users with 0 score only we can do the following:
    */
    if (resultSet.getInt("score") == 0) {
        User user = new User();
        user.setId(resultSet.getInt("id"));
        user.setName(resultSet.getString("name"));
        return user;
    }
    return null;
});

// Just wait for the query to complete. When it's time, whenComplete method is executed
future.whenComplete((users, exception) -> {
    if (exception != null) {
        // you can handle the error
        return;
    }
    // "users" is the list of results, extracted from ResultSet with ResultSetRowMapper (users with 0 score)
    // note that the list can be empty, but never null
    for (User user : users) 
        player.sendMessage(user.getId() + " - " + user.getName());
});

Example on getting a single result by using an SQL statement with single parameter:

// make sure to import java.sql.Types
String sql = "SELECT * FROM users WHERE id = ?";
CompletableFuture<User> future = asyncDb.queryForObject(sql, new Integer[] {1}, (resultSet, rowNumber) -> {
    // Code inside this lambda will be executed once
    return new User(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3));
}, Types.INTEGER);

// Same logic as before
future.whenComplete((user, exception) -> {
    if (exception != null) {
        // you can handle the error
        return;
    }
    // Warning: a single result can be null
    if (user != null)
        player.sendMessage("Score of " + user.getName() + ": " + user.getScore());
});

Example on getting a single result by using an SQL statement with multiple parameters:

String sql = "SELECT * FROM users WHERE id = ? OR score > ?";
// If parameter types are different we must use new Object[] {...}
// e.g. new Object[] {1, "HelloSecondParam", 4.4, otherRandomVariable}
CompletableFuture<User> future = asyncDb.queryForObject(sql, new Integer[] {1, 10}, (resultSet, rowNumber) -> {
    return new User(resultSet.getInt(1), resultSet.getString(2));
}, Types.INTEGER, Types.INTEGER);

// Same logic as before
future.whenComplete((user, exception) -> {
    if (exception != null) {
        // you can handle the error
        return;
    }
    // Warning: a single result can be null
    if (user != null) {
        // things
    }
});

ATTENTION: SQL Types in methods' parameters are not mandatory. Avoiding SQL types will let Mystral to use the PreparedStatement#setObject method.
This method's behavior depends on the JDBC Driver you're using. Each JDBC Driver has its own PreparedStatement class' implementation. Be careful when not specifying SQL Types: this could lead to unpredictable results.

Single update (delete, insert, update, create, drop...)

These methods can handle every type of update statement (static or not).

Every update method returns the number of the affected rows. By setting getGeneratedKeys argument on true, the method will return the primary key of the generated row (if it was really created). Note: right now, this works with numeric primary keys only. "getGeneratedKeys" is useless when you are not using an INSERT statement.

The usage of these methods is as simple as the query ones. Here are some examples.

Update with parametrized SQL statement:

String sql = "INSERT INTO users VALUES(?, ?, ?)";
CompletableFuture<Integer> future = asyncDb.update(sql, new Object[] {3, "ErMandarone", 10}, false, Types.INTEGER, Types.VARCHAR, Types.INTEGER);

// Same logic as before
future.whenComplete((integer, exception) -> {
    if (exception != null) {
        return; // you can handle the error
    }
    System.out.println(integer); // Expected 1
}

Update with static SQL statement:

String sql = "INSERT INTO users VALUES(null, 'Helo', 50)";
CompletableFuture<Integer> future = asyncDb.update(sql, true, Types.NULL, Types.VARCHAR, Types.INTEGER);

// Same logic as before
future.whenComplete((integer, exception) -> {
    if (exception != null) {
        // you can handle the error
        return;
    }
    System.out.println(integer); // Expected the primary key of this new row
}

Batch update (delete, insert, update, create, drop...)

These methods perform multiple updates by using the same SQL statement.

Right now, no results are supplied by Mystral's batch update methods. Anyway, you can handle possible exceptions.

Usage of these interfaces is encouraged when you are using these methods:

  • BatchSetter;
  • ParametrizedBatchSetter.

Also, you don't have to specify SQL Types when you're using these interfaces.
Read their documentations for further information.

Example with BatchSetter:

// Let's prepare 100 insert statements
List<User> users = new ArrayList<>();
for (int i = 0; i < 100; i++) 
    users.add(new User(i, "Test" + 1, 0));

String sql = "INSERT INTO users VALUES(?, ?, ?)";

CompletableFuture<Void> future = asyncDb.batchUpdate(sql, new BatchSetter() {
    @Override
    public void setValues(@NotNull PreparedStatement ps, int i) throws SQLException {
	    User user = users.get(i);
        ps.setInt(1, user.getId());
	    ps.setString(2, user.getName());
	    ps.setInt(3, 0); 
    }

    @Override
    public int getBatchSize() {
        return users.size();
    }
});

//Same logic as before
future.whenComplete((unused, exception) -> {
    if (exception != null) {
        // you can handle the error
    }
});

Example with ParametrizedBatchSetter:

List<User> users = coolMethodFor100Users(); // Let's assume that "users" is a list containing 100 different users
String sql = "INSERT INTO users VALUES(?, ?, ?)";

CompletableFuture<Void> future = asyncDb.batchUpdate(sql, users, (ps, user) -> {
    ps.setInt(1, user.getId());
    ps.setString(2, user.getName());
    ps.setInt(3, user.getScore());
});

//Same logic as before
future.whenComplete((unused, exception) -> {
    if (exception != null) {
        // you can handle the error
    }
});

A special thanks to xelverethx for her contribution.

You might also like...

BenDB - An fastest, qualified & easy to use multi database library

BenDB - An fastest, qualified & easy to use multi database library

BenDB - An fastest, qualified & easy to use multi database library

May 3, 2022

A Java library to query pictures with SQL-like language

A Java library to query pictures with SQL-like language

PicSQL A Java library to query pictures with SQL-like language. Features : Select and manipulate pixels of pictures in your disk with SQL-like dialect

Dec 25, 2022

A Java library to query pictures with SQL-like language.

A Java library to query pictures with SQL-like language.

PicSQL A Java library to query pictures with SQL-like language. Features : Select and manipulate pixels of pictures in your disk with SQL-like dialect

Dec 25, 2022

esProc SPL is a scripting language for data processing, with well-designed rich library functions and powerful syntax, which can be executed in a Java program through JDBC interface and computing independently.

esProc SPL is a scripting language for data processing, with well-designed rich library functions and powerful syntax, which can be executed in a Java program through JDBC interface and computing independently.

esProc esProc is the unique name for esProc SPL package. esProc SPL is an open-source programming language for data processing, which can perform comp

Dec 27, 2022

tuya-spring-boot-starter helps you efficiently create cloud development projects regarding the OpenAPI or message subscription capabilities. You can put all the focus on business logic without taking care of server-side programming nor relational databases.

English | 中文版 tuya-spring-boot-starter helps you efficiently create cloud development projects regarding the OpenAPI or message subscription capabilit

Dec 26, 2022

To quickly integrate your applications into the EdgeGallery platform, we provide the toolchain project to help developers quickly modify code and migrate applications to the platform.

Toolchain 工具链 工具链是MEC Developer开发者平台中的一个重要特性,当x86平台的App想要上车ARM平台时,底层的代码不可避免的需要进行修改或重写。 App提供者可以通过MEC Developer开发者平台中集成的工具链进行源代码分析,定位需要修改的源代码并根据指导意见进行修

Jan 7, 2022

OpenMap is an Open Source JavaBeans-based programmer's toolkit. Using OpenMap, you can quickly build applications and applets that access data from legacy databases and applications.

$Source: /cvs/distapps/openmap/README,v $ $RCSfile: README,v $ $Revision: 1.11 $ $Date: 2002/11/06 19:11:02 $ $Author: bmackiew $ OpenMap(tm) What

Nov 12, 2022

Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 6 and above, brought to you by Google.

Guice Latest release: 5.0.1 Documentation: User Guide, 5.0.1 javadocs, Latest javadocs Continuous Integration: Mailing Lists: User Mailing List Licens

Dec 29, 2022

Now redundant weka mirror. Visit https://github.com/Waikato/weka-trunk for the real deal

weka (mirror) Computing and Mathematical Sciences at the University of Waikato now has an official github organization including a read-only git mirro

Dec 16, 2022

Winfoom is an HTTP(s) proxy server facade that allows applications to authenticate through the proxy without having to deal with the actual handshake.

Winfoom is an HTTP(s) proxy server facade that allows applications to authenticate  through the proxy without having to deal with the actual handshake.

winfoom Basic Proxy Facade for NTLM, Kerberos, SOCKS and Proxy Auto Config file proxies To help this project please give it a star ⭐ Overview Winfoom

Dec 8, 2022

A Java library for quickly and efficiently parsing and writing UUIDs

fast-uuid fast-uuid is a Java library for quickly and efficiently parsing and writing UUIDs. It yields the most dramatic performance gains when compar

Jan 1, 2023

QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties

QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties

QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties quickperf.io 📙 Documentation Annotations

Dec 15, 2022

Mars - Object Relational Mapping Framework for MongoDB (MongoDB ORM)

Mars   -  Object Relational Mapping  Framework for MongoDB  (MongoDB ORM)

Mars Object Relational Mapping Framework for MongoDB 致自己 造自己的轮子,让别人去说 ; What is Mars Mars is a unified driver platform product developed by Shanghai J

Nov 17, 2022

Allows you to use the MongoDB query syntax to query your relational database.

Allows you to use the MongoDB query syntax to query your relational database.

Spring Data JPA MongoDB Expressions How it works: Customize JPA Repository base class: @SpringBootApplication @EnableJpaRepositories(repositoryBaseCla

Dec 27, 2022

Reladomo is an enterprise grade object-relational mapping framework for Java.

Reladomo What is it? Reladomo is an object-relational mapping (ORM) framework for Java with the following enterprise features: Strongly typed compile-

Nov 2, 2022

Hibernate's core Object/Relational Mapping functionality

Hibernate ORM is a library providing Object/Relational Mapping (ORM) support to applications, libraries, and frameworks. It also provides an implement

Jan 9, 2023

Database Subsetting and Relational Data Browsing Tool.

Database Subsetting and Relational Data Browsing Tool.

Jailer Database Tool Jailer is a tool for database subsetting and relational data browsing. The Subsetter exports consistent, referentially intact row

Jan 7, 2023

Relational database project, PC Builder, for the Database Systems Design course.

README: Starting the Progam: This program was built and ran on the Eclipse IDE. To run, first create the database, "ty_daniel_db", using the ty_dani

Jan 6, 2022

Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.

Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.

Testcontainers Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium we

Jan 9, 2023
Comments
Releases(1.4.6-SNAPSHOT)
Owner
null
Database Subsetting and Relational Data Browsing Tool.

Jailer Database Tool Jailer is a tool for database subsetting and relational data browsing. The Subsetter exports consistent, referentially intact row

Wisser 1.5k Jan 7, 2023
Change data capture for a variety of databases. Please log issues at https://issues.redhat.com/browse/DBZ.

Copyright Debezium Authors. Licensed under the Apache License, Version 2.0. The Antlr grammars within the debezium-ddl-parser module are licensed unde

Debezium 7.9k Dec 26, 2022
A tool based on mysql-connector to simplify the use of databases, tables & columns

Description A tool based on mysql-connector to simplify the use of databases, tables & columns. This tool automatically creates the databases & tables

nz 6 Nov 17, 2022
EBQuery allows you to easily access databases through a REST API.

EBQuery Table of Contents Introduction - Enterprise Backend as a Service Requirements Getting started Using EBQuery Features Introduction - Enterprise

null 15 Nov 9, 2021
A simple-to-use storage ORM supporting several databases for Java.

Storage Handler This is a library based off of my old storage handler within my queue revamp. It's for easy storage handling for multiple platforms. N

NV6 7 Jun 22, 2022
This is an automated library software built in Java Netbeans to reduce manual efforts of the librarian, students to ensure smooth functioning of library by involving RFIDs.

Advanced-Library-Automation-System This is an advanced automated library software built in Java Netbeans to reduce manual efforts of the librarian, st

DEV_FINWIZ 14 Dec 6, 2022
sql2o is a small library, which makes it easy to convert the result of your sql-statements into objects. No resultset hacking required. Kind of like an orm, but without the sql-generation capabilities. Supports named parameters.

sql2o Sql2o is a small java library, with the purpose of making database interaction easy. When fetching data from the database, the ResultSet will au

Lars Aaberg 1.1k Dec 28, 2022
A RatingBar library for android, you can customize size, spacing, color and image easily, and support right to left.

AndRatingBar A RatingBar library for android, you can customize size, spacing, color and image easily, and support right to left. 安卓RatingBar终极方案,继承自原

dqq 271 Aug 14, 2021
A Java library designed to make making decisions based on the current operating system easier.

Java OS Independence ...or JOSI for short, is a simple and lightweight Java library designed to make making decisions based on the current operating s

null 38 Dec 30, 2022
Simple but powerful SQL library for tiny projects

KiORM - Simple and powerful MySQL Java library for tiny projects Notice: KiORM is still in SNAPSHOT state. The code is not tested, there is no Javadoc

Rikonardo 2 Sep 13, 2022