A Java client for Tarantool
Clone or download
Pull request Compare This branch is 139 commits ahead, 1 commit behind dork:master.
ztarvos and Totktonada add round robin fail-over for a client
Added cluster-ready client implementation that
would fail-over to the next configured server in a
round-robin fashion.

Closes #37
Latest commit 935093d Dec 13, 2018

README.md

Java connector for Tarantool 1.7.4+

Coverage Status

Join the chat at https://gitter.im/tarantool/tarantool-java

To get the Java connector for Tarantool 1.6.9, visit this GitHub page.

Table of contents

Getting started

  1. Add a dependency to your pom.xml file.
<dependency>
  <groupId>org.tarantool</groupId>
  <artifactId>connector</artifactId>
  <version>1.7.4</version>
</dependency>
  1. Configure TarantoolClientConfig.
TarantoolClientConfig config = new TarantoolClientConfig();
config.username = "test";
config.password = "test";
  1. Implement your SocketChannelProvider. It should return a connected SocketChannel.
SocketChannelProvider socketChannelProvider = new SocketChannelProvider() {
           @Override
           public SocketChannel get(int retryNumber, Throwable lastError) {
               if (lastError != null) {
                   lastError.printStackTrace(System.out);
               }
               try {
                   return SocketChannel.open(new InetSocketAddress("localhost", 3301));
               } catch (IOException e) {
                   throw new IllegalStateException(e);
               }
           }
       };

Here you could also implement some reconnection or fallback policy. Remember that TarantoolClient adopts a fail-fast policy when a client is not connected.

The TarantoolClient will stop functioning if your implementation of a socket channel provider raises an exception or returns a null. You will need a new instance of client to recover. Hence, you should only throw in case you have met unrecoverable error.

Below is an example of SocketChannelProvider implementation that handles short tarantool restarts.

SocketChannelProvider socketChannelProvider = new SocketChannelProvider() {
    @Override
    public SocketChannel get(int retryNumber, Throwable lastError) {
        long deadline = System.currentTimeMillis() + RESTART_TIMEOUT;
        while (!Thread.currentThread().isInterrupted()) {
            try {
                return SocketChannel.open(new InetSocketAddress("localhost", 3301));
            } catch (IOException e) {
                if (deadline < System.currentTimeMillis())
                    throw new RuntimeException(e);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        throw new RuntimeException(new TimeoutException("Connect timed out."));
    }
};
  1. Create a client.
TarantoolClient client = new TarantoolClientImpl(socketChannelProvider, config);

Notes:

  • TarantoolClient is thread-safe and asynchronous, so you should use one client inside the whole application.
  • TarantoolClient does not support name resolution for fields, indexes, spaces and so on. We highly recommend to use server-side Lua when working with named items. For example, you could create a data access object (DAO) with simple CRUD functions. If, for some reason, you do need client name resolution, you could create a function that returns necessary name-to-ID mappings.

TarantoolClient provides three interfaces to execute queries:

  • SyncOps - returns the operation result
  • AsyncOps - returns the operation result as a Future
  • FireAndForgetOps - returns the query ID

Feel free to override any method of TarantoolClientImpl. For example, to hook all the results, you could override this:

protected void complete(long code, FutureImpl<?> q);

Spring NamedParameterJdbcTemplate usage example

To configure sockets you should implements SQLSocketProvider and add socketProvider=abc.xyz.MySocketProvider to connect url. For example tarantool://localhost:3301?user=test&password=test&socketProvider=abc.xyz.MySocketProvider

NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(new DriverManagerDataSource("tarantool://localhost:3301?user=test&password=test"));
RowMapper<Object> rowMapper = new RowMapper<Object>() {
    @Override
    public Object mapRow(ResultSet resultSet, int i) throws SQLException {
        return Arrays.asList(resultSet.getInt(1), resultSet.getString(2));
    }
};

try {
    System.out.println(template.update("drop table hello_world", Collections.<String, Object>emptyMap()));
} catch (Exception ignored) {
}

System.out.println(template.update("create table hello_world(hello int not null PRIMARY KEY, world varchar(255) not null)", Collections.<String, Object>emptyMap()));
Map<String, Object> params = new LinkedHashMap<String, Object>();
params.put("text", "hello world");
params.put("id", 1);

System.out.println(template.update("insert into hello_world(hello, world) values(:id,:text)", params));
System.out.println(template.query("select * from hello_world", rowMapper));

System.out.println(template.query("select * from hello_world where hello=:id", Collections.singletonMap("id", 1), rowMapper));

For more implementation details, see API documentation.

Where to get help

Got problems or questions? Post them on Stack Overflow with the tarantool and java tags, or use these tags to search the existing knowledge base for possible answers and solutions.

Building

To run tests

./mvnw clean test