= Reactive MySQL Client
:PREPARED_PARAMS: `?`

The Reactive MySQL Client is a client for MySQL with a straightforward API focusing on
scalability and low overhead.

The client is reactive and non-blocking, allowing to handle many database connections with a single thread.

*Features*

* Event driven
* Lightweight
* Built-in connection pooling
* Prepared queries caching
* Cursor support
* Row streaming
* RxJava API
* Direct memory to object without unnecessary copies
* Complete data type support
* Stored Procedures support
* TLS/SSL support
* Query pipelining
* MySQL utilities commands support
* Working with MySQL and MariaDB
* Rich collation and charset support
* Unix domain socket

== Usage

To use the Reactive MySQL Client add the following dependency to the _dependencies_ section of your build descriptor:

* Maven (in your `pom.xml`):

[source,xml]
----
<dependency>
  <groupId>${maven.groupId}</groupId>
  <artifactId>${maven.artifactId}</artifactId>
  <version>${maven.version}</version>
</dependency>
----
* Gradle (in your `build.gradle` file):

[source,groovy]
----
dependencies {
  compile '${maven.groupId}:${maven.artifactId}:${maven.version}'
}
----

== Getting started

Here is the simplest way to connect, query and disconnect

[source,$lang]
----
{@link examples.MySQLClientExamples#gettingStarted()}
----

== Connecting to MySQL

Most of the time you will use a pool to connect to MySQL:

[source,$lang]
----
{@link examples.MySQLClientExamples#connecting01}
----

The pooled client uses a connection pool and any operation will borrow a connection from the pool
to execute the operation and release it to the pool.

If you are running with Vert.x you can pass it your Vertx instance:

[source,$lang]
----
{@link examples.MySQLClientExamples#connecting02}
----

You need to release the pool when you don't need it anymore:

[source,$lang]
----
{@link examples.MySQLClientExamples#connecting03}
----

When you need to execute several operations on the same connection, you need to use a client
{@link io.vertx.mysqlclient.MySQLConnection connection}.

You can easily get one from the pool:

[source,$lang]
----
{@link examples.MySQLClientExamples#connecting04}
----

Once you are done with the connection you must close it to release it to the pool, so it can be reused.

== Command pipelining

In some use cases, command pipelining can improve database access performance.

You can configure the client to use pipelining

[source,$lang]
----
{@link examples.MySQLClientExamples#clientPipelining}
----

The default pipelining limit is `1` which disables pipelining.

[CAUTION]
====
Do not enable pipelining if you use a proxy that does not support it.
Otherwise, the proxy might close client connections abruptly.
====

== Pool versus pooled client

The {@link io.vertx.mysqlclient.MySQLPool} allows you to create a pool or a pooled client

[source,$lang]
----
{@link examples.MySQLClientExamples#poolVersusPooledClient}
----

- pool operations are not pipelined, only connections acquired from the pool are pipelined
- pooled client operations are pipelined, you cannot acquire a connection from a pooled client

== Pool sharing

include::pool_sharing.adoc[]

=== Unix Domain Socket

Sometimes for simplicity, security or performance reasons, it is required to connect via a https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_socket[Unix Domain Socket].

Since the JVM does not support domain sockets, first you must add native transport extensions to your project.

* Maven (in your `pom.xml`):

[source,xml]
----
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-transport-native-epoll</artifactId>
  <version>${netty.version}</version>
  <classifier>linux-x86_64</classifier>
</dependency>
----
* Gradle (in your `build.gradle` file):

[source,groovy]
----
dependencies {
  compile 'io.netty:netty-transport-native-epoll:${netty.version}:linux-x86_64'
}
----

NOTE: The native `epoll` support for ARM64 can also be added with the classifier `linux-aarch64`.

NOTE: If there are Mac users in your team, add `netty-transport-native-kqueue` with the classifier `osx-x86_64`.

Then set the path to the domain socket in {@link io.vertx.mysqlclient.MySQLConnectOptions#setHost MySQLConnectOptions#setHost}:

[source,$lang]
----
{@link examples.MySQLClientExamples#connectWithUnixDomainSocket}
----

More information about native transports can be found in the [Vert.x documentation](https://vertx.io/docs/vertx-core/java/#_native_transports).

== Configuration

There are several alternatives for you to configure the client.

=== Data Object

A simple way to configure the client is to specify a `MySQLConnectOptions` data object.

[source,$lang]
----
{@link examples.MySQLClientExamples#configureFromDataObject(io.vertx.core.Vertx)}
----

==== collations and character sets

The Reactive MySQL client supports configuring collations or character sets and map them to a correlative `java.nio.charset.Charset`.
For example, you can specify charset for a connection like

[source,$lang]
----
{@link examples.MySQLClientExamples#configureConnectionCharset()}
----

The Reactive MySQL Client will take `utf8mb4` as the default charset. String values like password and error messages are always decoded in `UTF-8` charset.

`characterEncoding` option is used to determine which Java charset will be used to encode String values such as query string and parameter values, the charset is `UTF-8` by default and if it's set to `null` then the client will use the default Java charset instead.

You can also specify collation for a connection like

[source,$lang]
----
{@link examples.MySQLClientExamples#configureConnectionCollation()}
----

Note setting a collation on the data object will override the *charset* and *characterEncoding* option.

You can execute SQL `SHOW COLLATION;` or `SHOW CHARACTER SET;` to get the supported collations and charsets by the server.

More information about MySQL charsets and collations can be found in the https://dev.mysql.com/doc/refman/8.0/en/charset.html[MySQL Reference Manual].

==== connection attributes

You can also configure the connection attributes with the `setProperties` or `addProperty` methods. Note `setProperties` will override the default client properties.

[source,$lang]
----
{@link examples.MySQLClientExamples#configureConnectionAttributes()}
----

More information about client connection attributes can be found in the https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html[MySQL Reference Manual].

==== useAffectedRows

You can configure the `useAffectedRows` option to decide whether to set `CLIENT_FOUND_ROWS` flag when connecting to the server. If the `CLIENT_FOUND_ROWS` flag is specified then the affected rows count is the numeric value of rows found rather than affected.

More information about this can be found in the https://dev.mysql.com/doc/refman/8.0/en/mysql-affected-rows.html[MySQL Reference Manual]

=== Connection URI

Apart from configuring with a `MySQLConnectOptions` data object, We also provide you an alternative way to connect when you want to configure with a connection URI:

[source,$lang]
----
{@link examples.MySQLClientExamples#configureFromUri(io.vertx.core.Vertx)}
----

More information about connection string formats can be found in the https://dev.mysql.com/doc/refman/8.0/en/connecting-using-uri-or-key-value-pairs.html#connecting-using-uri[MySQL Reference Manual].

Currently, the client supports the following parameter keys (case-insensitive):

* `host`
* `port`
* `user`
* `password`
* `schema`
* `socket`
* `useAffectedRows`

NOTE: Configuring parameters in connection URI will override the default properties.

== Connect retries

You can configure the client to retry when a connection fails to be established.

[source,$lang]
----
{@link examples.MySQLClientExamples#reconnectAttempts}
----

include::queries.adoc[leveloffset=1]

== MySQL LAST_INSERT_ID

You can get the auto incremented value if you insert a record into the table.

[source,$lang]
----
{@link examples.MySQLClientExamples#lastInsertId(io.vertx.sqlclient.SqlClient)}
----

More information can be found in https://dev.mysql.com/doc/refman/8.0/en/getting-unique-id.html[How to Get the Unique ID for the Last Inserted Row].

include::connections.adoc[]

include::transactions.adoc[]

include::cursor.adoc[]

== Tracing queries

include::tracing.adoc[]

== MySQL type mapping

Currently the client supports the following MySQL types

* BOOL,BOOLEAN (`java.lang.Byte`)
* TINYINT (`java.lang.Byte`)
* TINYINT UNSIGNED(`java.lang.Short`)
* SMALLINT (`java.lang.Short`)
* SMALLINT UNSIGNED(`java.lang.Integer`)
* MEDIUMINT (`java.lang.Integer`)
* MEDIUMINT UNSIGNED(`java.lang.Integer`)
* INT,INTEGER (`java.lang.Integer`)
* INTEGER UNSIGNED(`java.lang.Long`)
* BIGINT (`java.lang.Long`)
* BIGINT UNSIGNED(`io.vertx.sqlclient.data.Numeric`)
* FLOAT (`java.lang.Float`)
* FLOAT UNSIGNED(`java.lang.Float`)
* DOUBLE (`java.lang.Double`)
* DOUBLE UNSIGNED(`java.lang.Double`)
* BIT (`java.lang.Long`)
* NUMERIC (`io.vertx.sqlclient.data.Numeric`)
* NUMERIC UNSIGNED(`io.vertx.sqlclient.data.Numeric`)
* DATE (`java.time.LocalDate`)
* DATETIME (`java.time.LocalDateTime`)
* TIME (`java.time.Duration`)
* TIMESTAMP (`java.time.LocalDateTime`)
* YEAR (`java.lang.Short`)
* CHAR (`java.lang.String`)
* VARCHAR (`java.lang.String`)
* BINARY (`io.vertx.core.buffer.Buffer`)
* VARBINARY (`io.vertx.core.buffer.Buffer`)
* TINYBLOB (`io.vertx.core.buffer.Buffer`)
* TINYTEXT (`java.lang.String`)
* BLOB (`io.vertx.core.buffer.Buffer`)
* TEXT (`java.lang.String`)
* MEDIUMBLOB (`io.vertx.core.buffer.Buffer`)
* MEDIUMTEXT (`java.lang.String`)
* LONGBLOB (`io.vertx.core.buffer.Buffer`)
* LONGTEXT (`java.lang.String`)
* ENUM (`java.lang.String`)
* SET (`java.lang.String`)
* JSON (`io.vertx.core.json.JsonObject`, `io.vertx.core.json.JsonArray`, `Number`, `Boolean`, `String`, `io.vertx.sqlclient.Tuple#JSON_NULL`)
* GEOMETRY(`io.vertx.mysqlclient.data.spatial.*`)

Tuple decoding uses the above types when storing values

Note: In Java there is no specific representations for unsigned numeric values, so this client will convert an unsigned value to the correlated Java type.

=== Implicit type conversion

The Reactive MySQL Client supports implicit type conversions when executing a prepared statement.
Suppose you have a `TIME` column in your table, the two examples below will both work here.

[source,$lang]
----
{@link examples.MySQLClientExamples#implicitTypeConversionExample(io.vertx.sqlclient.SqlClient)}
----

The MySQL data type for encoding will be inferred from the parameter values and here is the type mapping

|===
|Parameter value type |encoding MySQL type

|null
|MYSQL_TYPE_NULL

|java.lang.Byte
|MYSQL_TYPE_TINY

|java.lang.Boolean
|MYSQL_TYPE_TINY

|java.lang.Short
|MYSQL_TYPE_SHORT

|java.lang.Integer
|MYSQL_TYPE_LONG

|java.lang.Long
|MYSQL_TYPE_LONGLONG

|java.lang.Double
|MYSQL_TYPE_DOUBLE

|java.lang.Float
|MYSQL_TYPE_FLOAT

|java.time.LocalDate
|MYSQL_TYPE_DATE

|java.time.Duration
|MYSQL_TYPE_TIME

|java.time.LocalTime
|MYSQL_TYPE_TIME

|io.vertx.core.buffer.Buffer
|MYSQL_TYPE_BLOB

|java.time.LocalDateTime
|MYSQL_TYPE_DATETIME

|io.vertx.mysqlclient.data.spatial.*
|MYSQL_TYPE_BLOB

|default
|MYSQL_TYPE_STRING
|===

=== Handling BOOLEAN

In MySQL `BOOLEAN` and `BOOL` data types are synonyms for `TINYINT(1)`. A value of zero is considered false, non-zero values are considered true.
A `BOOLEAN` data type value is stored in `Row` or `Tuple` as `java.lang.Byte` type, you can call `Row#getValue` to retrieve it as a `java.lang.Byte` value,
or you can call `Row#getBoolean` to retrieve it as `java.lang.Boolean` value.

[source,$lang]
----
{@link examples.MySQLClientExamples#booleanExample01(io.vertx.sqlclient.SqlClient)}
----

When you want to execute a prepared statement with a param of a `BOOLEAN` value, you can simply add the `java.lang.Boolean` value to the params list.

[source,$lang]
----
{@link examples.MySQLClientExamples#booleanExample02(io.vertx.sqlclient.SqlClient)}
----

=== Handling JSON

MySQL `JSON` data type is represented by the following Java types:

- `String`
- `Number`
- `Boolean`
- `io.vertx.core.json.JsonObject`
- `io.vertx.core.json.JsonArray`
- `io.vertx.sqlclient.Tuple#JSON_NULL` for representing the JSON null literal

[source,$lang]
----
{@link examples.MySQLClientExamples#jsonExample()}
----

=== Handling BIT
The `BIT` data type is mapped to `java.lang.Long` type, but Java has no notion of unsigned numeric values, so if you want to insert or update a record with the max value of `BIT(64)`, you can do some tricks setting the parameter to `-1L`.

=== Handling TIME

MySQL `TIME` data type can be used to represent either time of a day or a time interval which ranges from `-838:59:59` to `838:59:59`. In Reactive MySQL client the `TIME` data type is mapped to `java.time.Duration` natively, but you can also retrieve it as a `java.time.LocalTime` via `Row#getLocalTime` accessor.

=== Handling NUMERIC

The {@link io.vertx.sqlclient.data.Numeric} Java type is used to represent the MySQL `NUMERIC` type.

[source,$lang]
----
{@link examples.MySQLClientExamples#numericExample(io.vertx.sqlclient.Row)}
----

=== Handling ENUM

MySQL supports ENUM data type and the client retrieves these types as String data type.

You can encode Java enums as String like this:

[source,$lang]
----
{@link examples.MySQLClientExamples#enumeratedType01Example}
----

You can retrieve the ENUM column as Java enums like this:

[source,$lang]
----
{@link examples.MySQLClientExamples#enumeratedType02Example}
----

=== Handling GEOMETRY

MYSQL `GEOMETRY` data type is also supported, Here are some examples showing that you can handle the geometry data in Well-Known Text (WKT) format or Well-Known Binary (WKB) format, the data are decoded as MySQL TEXT OR BLOB data type. There are many great third-party libraries for handling data in this format.

You can fetch spatial data in WKT format:

[source,$lang]
----
{@link examples.MySQLClientExamples#geometryExample01(io.vertx.sqlclient.SqlClient)}
----

Or you can fetch spatial data in WKB format:

[source,$lang]
----
{@link examples.MySQLClientExamples#geometryExample02(io.vertx.sqlclient.SqlClient)}
----

We also provide you a simple way to handle the geometry data type in Reactive MySQL Client.

You can retrieve the geometry data as Vert.x Data Object:

[source,$lang]
----
{@link examples.MySQLClientExamples#geometryExample03(io.vertx.sqlclient.SqlClient)}
----

You can also take it as a prepared statement parameter in a WKB representation.

[source,$lang]
----
{@link examples.MySQLClientExamples#geometryExample04(io.vertx.sqlclient.SqlClient)}
----

== Collector queries

You can use Java collectors with the query API:

[source,$lang]
----
{@link examples.MySQLClientExamples#collector01Example(io.vertx.sqlclient.SqlClient)}
----

The collector processing must not keep a reference on the {@link io.vertx.sqlclient.Row} as
there is a single row used for processing the entire set.

The Java `Collectors` provides many interesting predefined collectors, for example you can
create easily create a string directly from the row set:

[source,$lang]
----
{@link examples.MySQLClientExamples#collector02Example(io.vertx.sqlclient.SqlClient)}
----

== MySQL Stored Procedure

You can run stored procedures in queries. The result will be retrieved from the server following the https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase_sp.html[MySQL protocol] without any magic here.

[source,$lang]
----
{@link examples.MySQLClientExamples#storedProcedureExample(io.vertx.sqlclient.SqlClient)}
----

Note: Prepared statements binding OUT parameters is not supported for now.

== MySQL LOCAL INFILE

This client supports for handling the LOCAL INFILE Request, if you want to load data from a local file into the server, you can use query
`LOAD DATA LOCAL INFILE '<filename>' INTO TABLE <table>;`. More information can be found in the https://dev.mysql.com/doc/refman/8.0/en/load-data.html[MySQL Reference Manual].

== Authentication

=== Default authentication plugin

This client supports for specifying the default authentication plugin to use at the connection start.
Currently the following plugins are supported:

- mysql_native_password
- caching_sha2_password
- mysql_clear_password

[source,$lang]
----
{@link examples.MySQLClientExamples#defaultAuthPluginExample}
----

=== New authentication method introduced in MySQL 8

MySQL 8.0 introduces a new authentication method named `caching_sha2_password` and it's the default one to authenticate.
In order to connect to the server using this new authentication method, you need either use a secure connection(i.e. enable TLS/SSL) or exchange the encrypted password using an RSA key pair to avoid leaks of password. The RSA key pair is automatically exchanged during the communication, but the server RSA public key may be hacked during the process since it's transferred on a insecure connection.
So if you're on a insecure connection and want to avoid the risk of exposing the server RSA public key, you can set the server RSA public key like this:

[source,$lang]
----
{@link examples.MySQLClientExamples#rsaPublicKeyExample}
----

More information about the `caching_sha2_password` authentication method can be found in the https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html[MySQL Reference Manual].

== Using SSL/TLS

To configure the client to use SSL connection, you can configure the {@link io.vertx.mysqlclient.MySQLConnectOptions}
like a Vert.x `NetClient`.
All https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl-mode[SSL modes] are supported and you are able to configure `sslmode`. The client is in `DISABLED` SSL mode by default.
`ssl` parameter is kept as a mere shortcut for setting `sslmode`. `setSsl(true)` is equivalent to `setSslMode(VERIFY_CA)` and `setSsl(false)` is equivalent to `setSslMode(DISABLED)`.

[source,$lang]
----
{@link examples.MySQLClientExamples#tlsExample}
----

More information can be found in the http://vertx.io/docs/vertx-core/java/#ssl[Vert.x documentation].

== MySQL utility command

Sometimes you want to use MySQL utility commands and we provide support for this.
More information can be found in the https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase_utility.html[MySQL utility commands].

=== COM_PING

You can use `COM_PING` command to check if the server is alive. The handler will be notified if the server responds to the PING, otherwise the handler will never be called.

[source,$lang]
----
{@link examples.MySQLClientExamples#pingExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_RESET_CONNECTION

You can reset the session state with `COM_RESET_CONNECTION` command, this will reset the connection state like:
- user variables
- temporary tables
- prepared statements

[source,$lang]
----
{@link examples.MySQLClientExamples#resetConnectionExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_CHANGE_USER

You can change the user of the current connection, this will perform a re-authentication and reset the connection state like `COM_RESET_CONNECTION`.

[source,$lang]
----
{@link examples.MySQLClientExamples#changeUserExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_INIT_DB

You can use `COM_INIT_DB` command to change the default schema of the connection.

[source,$lang]
----
{@link examples.MySQLClientExamples#initDbExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_STATISTICS

You can use `COM_STATISTICS` command to get a human readable string of some internal status variables in MySQL server.

[source,$lang]
----
{@link examples.MySQLClientExamples#statisticsExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_DEBUG

You can use `COM_DEBUG` command to dump debug info to the MySQL server's STDOUT.

[source,$lang]
----
{@link examples.MySQLClientExamples#debugExample(io.vertx.mysqlclient.MySQLConnection)}
----

=== COM_SET_OPTION

You can use `COM_SET_OPTION` command to set options for the current connection. Currently only `CLIENT_MULTI_STATEMENTS` can be set.

For example, you can disable `CLIENT_MULTI_STATEMENTS` with this command.

[source,$lang]
----
{@link examples.MySQLClientExamples#setOptionExample01(io.vertx.mysqlclient.MySQLConnection)}
----

== MySQL and MariaDB version support matrix

[cols="^,^,^,^", options="header"]
|====

2+| MySQL
2+| MariaDB

| Version | Supported | Version | Supported

|`5.5`
|&#10004;
|`10.1`
|&#10004;

|`5.6`
|&#10004;
|`10.2`
|&#10004;

|`5.7`
|&#10004;
|`10.3`
|&#10004;

|`8.0`
|&#10004;
|`10.4`
|&#10004;

|====

Known issues:

- Reset connection utility command does not work in MySQL 5.5, 5.6 and MariaDB 10.1
- Change user utility command is not supported with MariaDB 10.2 and 10.3

== Pitfalls & Good Practices

Here are some good practices for you to avoid common pitfalls when using the Reactive MySQL Client.

=== prepared statement count limit

Sometimes you might meet the notorious error `Can't create more than max_prepared_stmt_count statements (current value: 16382)`, this is because the server has reached the limit of total number of prepared statement.

You can adjust the server system variable `max_prepared_stmt_count` but it has an upper bound value so you can't get rid of the error in this way.

The best way to alleviate this is enabling prepared statement caching, so the prepared statements with the same SQL string could be reused and the client does not have to create a brand new prepared statement for every request.
The prepared statement will be automatically closed after the statement is executed.
In this way the chances of reaching the limit could be greatly reduced though it could not be totally eliminated.

You can also manage the lifecycle of prepared statements manually by creating a `PreparedStatement` object via `SqlConnection#prepare` interface so that you can choose when to deallocate the statement handle, or even use the https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html[SQL syntax prepared statement].

=== demystifying prepared batch

There is time when you want to batch insert data into the database, you can use `PreparedQuery#executeBatch` which provides a simple API to handle this.
Keep in mind that MySQL does not natively support batching protocol so the API is only a sugar by executing the prepared statement one after another, which means more network round trips are required comparing to inserting multiple rows by executing one prepared statement with a list of values.

=== tricky DATE & TIME data types

Handling MYSQL DATE and TIME data types especially with time zones is tricky therefore the Reactive MySQL Client does no magic transformation for those values.

* MySQL DATETIME data type does not contain time zone info, so what you get is identical to what you set no matter what time zone is in the current session.
* MySQL TIMESTAMP data type contains time zone info, so when you set or get the value it's always transformed by the server with the timezone set in the current session.

== Advanced pool configuration

include::pool_config.adoc[]
