eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Introduction

In this tutorial, we’ll take a look at the Apache IoTDB database. We’ll see what it is, how to use it and what we can do with it.

2. What is IoTDB

IoTDB is a free, open-source database designed for storing time-series data. It’s designed with IoT devices in mind, but can be used for storing any series of metrics or recordings that are identified by their timestamp. It’s also designed to be SQL compatible, so integrating it into our applications is easier.

Since IoTDB is designed with IoT devices in mind, its storage structure reflects this. Our databases, timeseries and data fields are typically modelled as a tree structure that reflects the fact that we’re recording different pieces of data from different devices, potentially of a range of types.

For example, we might want to record the speed of turbines as they vary over time. We could record this into the timeseries root.baeldung.turbine.device1.speed. This breaks down as:

  • root.baeldung – our database
  • turbine.device1 – our device
  • speed – the data we want to record

If we need to record the same data about multiple devices, we simply create multiple timeseries to record into,

3. Running IoTDB

IoTDB consists of three different services that can be used together:

  • Config nodes
  • Data nodes
  • Optionally – AI nodes

We can run this in a standalone mode, where we have a single process that consists of a Config node and a Data node in one. Alternatively, we can run this in a high-availability cluster. In this case, we need to run 3 Config nodes and at least 3 Data nodes, though we can add more as necessary. This ensures that we can continue to operate if a node fails.

In addition, we have the ability to run AI nodes that provide some AI models we can use to work with our data in real-time.

The easiest way to get started with IoTDB is to use Docker. Apache provide some starter Docker Compose files for running in various setups. For this article, we’re going to use the docker-compose-standalone.yml file.

This file assumes we’ve created a Docker network bridge for the container to use:

$ docker network create --driver=bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1  iotdb
ca767e800f66e4b067a6952420c784392661fd0aa21318e3ce3dc53fdad4ab00

We can then start our container:

$ docker compose up
[+] Running 1/1
 ✔ Container iotdb-service  Created       0.0s
Attaching to iotdb-service
.....
iotdb-service  | 2025-12-28 10:16:48,541 [main] INFO  o.a.i.db.service.DataNode:261
  - Congratulations, IoTDB DataNode is set up successfully. Now, enjoy yourself!
iotdb-service  | 2025-12-28 10:16:48,542 [main] INFO  o.a.i.db.service.DataNode:288
  - DataNode started
iotdb-service  | 2025-12-28 10:16:51,080 [pool-36-IoTDB-DataNodeInternalRPC-Processor-1]
  INFO  o.a.i.d.q.p.ClusterTopology:152 - [Topology] latest view from config-node: {1=[1]}

At this point, our database is running and ready to use.

4. Connecting to IoTDB

Now that our database is running, we need to be able to connect to it.

4.1. Command Line Interface

To administer our database, IoTDB includes a command-line interface for connecting to it. This is also installed inside the Docker containers, so we can easily run it using Docker:

$ docker exec -it iotdb-service start-cli.sh
---------------------
Starting IoTDB Cli
---------------------
 _____       _________  ______   ______
|_   _|     |  _   _  ||_   _ `.|_   _ \
  | |   .--.|_/ | | \_|  | | `. \ | |_) |
  | | / .'`\ \  | |      | |  | | |  __'.
 _| |_| \__. | _| |_    _| |_.' /_| |__) |
|_____|'.__.' |_____|  |______.'|_______/  version 2.0.5 (Build: 0917050)


Successfully login at 127.0.0.1:6667
IoTDB>

This gives us a command-line interface similar to the psql command from Postgres.

4.2. JDBC Driver

IoTDB also provides a number of different drivers for different programming languages. These include JDBC drivers that allow us to connect to the database from Java.

In order to use this, we first need to add the drivers to our project. If we’re using Maven, we can include this dependency in our pom.xml file:

<dependencies>
  <dependency>
    <groupId>org.apache.iotdb</groupId>
    <artifactId>iotdb-jdbc</artifactId>
    <version>2.0.5</version>
  </dependency>
</dependencies>

Once we’ve done this, we can use it the same as any other JDBC driver:

Class.forName("org.apache.iotdb.jdbc.IoTDBDriver");

try (Connection con = DriverManager
  .getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root")) {
    // use conn here
}

Since these are standard JDBC drivers, we can use them with anything that’s compatible – e.g. Spring JdbcTemplate.

5. Managing Databases

Within IoTDB, all of our data is stored in databases. These work similarly to other database management systems, comprising a collection of time series, each containing the corresponding data.

We create a new database using the CREATE DATABASE command:

IoTDB> CREATE DATABASE root.baeldung;
Msg: The statement is executed successfully.

We can see the databases that exist using the SHOW DATABASES command:

IoTDB> SHOW DATABASES;
+-------------+-----------------------+---------------------+-------------------+---------------------+
|     Database|SchemaReplicationFactor|DataReplicationFactor|TimePartitionOrigin|TimePartitionInterval|
+-------------+-----------------------+---------------------+-------------------+---------------------+
|root.baeldung|                      1|                    1|                  0|            604800000|
+-------------+-----------------------+---------------------+-------------------+---------------------+
Total line number = 1
It costs 0.107s

We can also delete the entire database using the DELETE DATABASE command:

IoTDB> DELETE DATABASE root.baeldung;
Msg: The statement is executed successfully.

Note that this is irreversible, so we need to be careful to ensure we’re doing it correctly.

6. Managing Timeseries

Within our database, we then collect data together into a timeseries. These are roughly analogous to tables in a traditional SQL database.

A simple timeseries consists of a timestamp and a value, which can be of any suitable type. We then record data in our timeseries as we generate it.

We can create our timeseries using the CREATE TIMESERIES command:

IoTDB> CREATE TIMESERIES root.baeldung.turbine.device1.speed FLOAT;
Msg: The statement is executed successfully.

Alternatively, we can create an aligned timeseries. These are a special case where there are several different measurements that are all related to the same input, and are all being made at the same instant. As such, we want to be able to relate these measurements to each other more easily. We create these using the CREATE ALIGNED TIMESERIES command:

IoTDB> CREATE ALIGNED TIMESERIES root.baeldung.car.device2(lat FLOAT, lng FLOAT);
Msg: The statement is executed successfully.

We can then see all of the timeseries that we’ve created using the SHOW TIMESERIES command:

IoTDB> SHOW TIMESERIES;
+-----------------------------------+-----+-------------+--------+--------+-----------+----+----------+--------+------------------+--------+
|                         Timeseries|Alias|     Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|ViewType|
+-----------------------------------+-----+-------------+--------+--------+-----------+----+----------+--------+------------------+--------+
|root.baeldung.turbine.device1.speed| null|root.baeldung|   FLOAT| GORILLA|        LZ4|null|      null|    null|              null|    BASE|
|      root.baeldung.car.device2.lng| null|root.baeldung|   FLOAT| GORILLA|        LZ4|null|      null|    null|              null|    BASE|
|      root.baeldung.car.device2.lat| null|root.baeldung|   FLOAT| GORILLA|        LZ4|null|      null|    null|              null|    BASE|
+-----------------------------------+-----+-------------+--------+--------+-----------+----+----------+--------+------------------+--------+
Total line number = 3
It costs 0.083s

Here we’ll see that the aligned timeseries actually shows up as the separate fields. This is how they’re stored, but because we created them as aligned time series, we interact with the data in them as a single entity.

We can also delete timeseries using the DELETE TIMESERIES command:

IoTDB> DELETE TIMESERIES root.baeldung.turbine.device1.speed;
Msg: The statement is executed successfully.

Note that if we wish to delete an aligned timeseries, we need to delete each field individually. We can’t delete the entire set in one go.

7. Managing Data

Now that we’ve got a database and some time series within it, we need some data within these. Similar to a traditional SQL database, we’re able to insert, query and delete records. However, we can’t update existing records in place.

7.1. Inserting Data

We insert data using the INSERT INTO command:

try (PreparedStatement stmt = con.prepareStatement("INSERT INTO root.baeldung.turbine.device1(timestamp, speed) VALUES (?, ?)")) {
    stmt.setObject(1, Instant.now().toEpochMilli());
    stmt.setObject(2, 10);
    stmt.executeUpdate();
}

Our timestamp here is provided as milliseconds since the epoch.

Alternatively, we can omit the timestamp from our statement:

try (PreparedStatement stmt = con.prepareStatement("INSERT INTO root.baeldung.turbine.device1(speed) VALUES (?)")) {
    stmt.setObject(1, 20);
    stmt.executeUpdate();
}

If we do this, IoTDB will use the current time instead of the value that we provided.

If we’re working with an aligned timeseries, we can insert data into all of our fields in a single statement:

try (PreparedStatement stmt = con.prepareStatement("INSERT INTO root.baeldung.car.device2(lat, lng) VALUES (?, ?)")) {
    stmt.setObject(1, 40.6892);
    stmt.setObject(2, 74.0445);
    stmt.executeUpdate();
}

Doing this helps ensure that the data always uses the same timestamp for all of the aligned fields. This is especially useful when IoTDB provides the current time for us.

7.2. Querying Data

Once we’ve added data to our timeseries, we need to be able to query it. We do this with the SELECT statement in the same way as with traditional SQL databases:

try (PreparedStatement stmt = con.prepareStatement("SELECT * FROM root.baeldung.turbine.device1")) {
    try (ResultSet rs = stmt.executeQuery()) {
        while (rs.next()) {
            long timestamp = rs.getLong(1);
            float speed = rs.getFloat(2);
            // Do something with the data
        }
    }
}

This works the same as with any SQL database, allowing us to specify the timeseries to query, the fields to return, and any conditions to apply to the returned data:

try (PreparedStatement stmt = con.prepareStatement("SELECT lat FROM root.baeldung.car.device2 WHERE timestamp = ?")) { 
    stmt.setObject(1, Instant.now().toEpochMilli());
    try (ResultSet rs = stmt.executeQuery()) {
        while (rs.next()) {
            long timestamp = rs.getLong(1);
            float lat = rs.getFloat(2);
            // Do something with the data
        }
    }
}

Note that we always get the timestamp for the records back, even if we didn’t request it. As such, restricting the returned fields is only useful when querying aligned timeseries that have multiple data fields to return.

8. Summary

In this article, we’ve taken a brief look at the IoTDB time-series database. There’s much more we can do with this system. Next time you need to work with data feeds from IoT devices, why not give it a try?

As usual, all of the examples from this article are available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)
guest
0 Comments
Oldest
Newest
Inline Feedbacks
View all comments