Building Time-Series Applications With Java and InfluxDB
InfluxDB brings time-oriented storage to Java applications, while Eclipse JNoSQL 1.1.18 simplifies integration through TimeSeriesTemplate and Jakarta Data repositories.
Join the DZone community and get the full member experience.
Join For FreeInfluxDB is essential for applications that analyze continuously changing data. In IoT, this includes tracking temperature, pressure, energy use, or machine telemetry over time. Financial systems use similar models for market prices, exchange rates, trading activity, portfolio values, and risk metrics. The key requirement is the ability to ingest large volumes of timestamped data and efficiently query current, historical, and evolving values.
This versatility makes InfluxDB valuable beyond traditional monitoring. Enterprises use it for observability, infrastructure metrics, logistics, industrial systems, customer activity, fraud detection, transaction trends, and business KPIs. When time is central to data storage and queries, a dedicated time-series database simplifies architecture and enables more intuitive queries.
Understanding InfluxDB
InfluxDB is designed to preserve data value by keeping its relationship to time. Instead of treating timestamps as standard columns, InfluxDB organizes data by time-based measurements, attributes, and values. Each record represents an observation at a specific moment, such as a sensor’s temperature, API latency, or asset price. This structure supports direct queries, including retrieving the latest value, assessing recent trends, or calculating averages over defined intervals.
This structure is ideal for workloads that produce continuous data. IoT devices generate millions of measurements, infrastructure platforms track ongoing metrics, and financial applications monitor prices and transactions. In these cases, data is usually appended, not updated, and queries often focus on recent values, time ranges, aggregations, or trends.
As a result, InfluxDB is well suited for modern architectures. Distributed applications, cloud platforms, microservices, connected devices, and real-time business systems all generate continuous temporal data. Beyond storage, applications have to efficiently query and aggregate this data to assess current conditions and understand system evolution.
The key point is that InfluxDB is not only an “IoT database.” InfluxDB is not limited to IoT use cases. It can serve as the temporal component in a more extensive polyglot architecture. For example, a relational database may manage transactional data, a document database may handle flexible aggregates, and InfluxDB can store the history of measurements, signals, and operational changes. When business needs require insight into how something evolves over time, this time-based specialization provides a significant architectural advantage.
Hands-On: Java With InfluxDB
Starting with Eclipse JNoSQL 1.1.18, Java applications can work with time-series databases through a consistent programming model. Let’s see this in practice with InfluxDB 3.
For this example, InfluxDB will run locally without authentication to simplify setup. This approach is suitable for development and demonstrations, but --without-auth must not be used in production.
Start InfluxDB 3 Core with Docker:
docker run -d \
--name influxdb-instance \
-p 8181:8181 \
influxdb:3.11.0-core \
influxdb3 serve \
--node-id jnosql \
--object-store memory \
--without-auth
Once the server is running, create the database used by the application:
docker exec influxdb-instance \
influxdb3 create database \
--host http://localhost:8181 \
metrics
Setting Up the Java Application
Eclipse JNoSQL uses Jakarta technologies such as CDI and JSON-B, along with Eclipse MicroProfile Config for externalized configuration. These APIs are available in runtimes including Open Liberty, Payara, Helidon, and Quarkus.
Beyond the standard JNoSQL dependencies, add the InfluxDB driver:
<dependency>
<groupId>org.eclipse.jnosql.databases</groupId>
<artifactId>jnosql-influxdb</artifactId>
<version>${jnosql.version}</version>
</dependency>
Then configure the connection through microprofile-config.properties:
jnosql.timeseries.database=metrics
jnosql.influxdb.url=http://localhost:8181
jnosql.influxdb.token=jnosql-influxdb-test-token
Since authentication is disabled for this local instance, the token serves only as a required placeholder for the driver configuration. In production, these values should be externalized and overridden using MicroProfile Config, aligning with Twelve-Factor App principles.
Modeling Time-Series Data
In this example, account transactions are modeled over time:
@Entity
public class AccountTransaction {
@Id
private Instant id;
@Column
private String account;
@Column
private BigDecimal amount;
@Column
private String currency;
@Column
private TransactionStatus status;
// constructors, getters, and setters
}
The transaction status can be represented with a simple enum:
public enum TransactionStatus {
APPROVED,
DECLINED,
PENDING
}
The key detail is the Instant identifier. Each transaction records a specific point in time, enabling queries for the latest state and historical navigation.
Using TimeSeriesTemplate
You can now insert transactions and query them using TimeSeriesTemplate:
public class App {
public static void main(String[] args) {
var firstTransaction = new AccountTransaction(
Instant.parse("2026-09-20T08:00:00Z"),
"account-42",
new BigDecimal("79.90"),
"EUR",
TransactionStatus.APPROVED
);
var secondTransaction = new AccountTransaction(
Instant.parse("2026-09-20T09:00:00Z"),
"account-42",
new BigDecimal("24.50"),
"EUR",
TransactionStatus.APPROVED
);
var latestTransaction = new AccountTransaction(
Instant.parse("2026-09-20T10:15:00Z"),
"account-42",
new BigDecimal("120.00"),
"EUR",
TransactionStatus.DECLINED
);
try (SeContainer container =
SeContainerInitializer.newInstance().initialize()) {
TimeSeriesTemplate template =
container.select(TimeSeriesTemplate.class).get();
template.insert(firstTransaction);
template.insert(secondTransaction);
template.insert(latestTransaction);
var currentStatus = template
.select(AccountTransaction.class)
.where("account")
.eq("account-42")
.orderBy("id")
.desc()
.limit(1)
.singleResult();
System.out.println(
"Current account status: " + currentStatus
);
var history = template
.select(AccountTransaction.class)
.where("account")
.eq("account-42")
.orderBy("id")
.desc()
.skip(1)
.limit(10)
.result();
System.out.println("Transaction history:");
history.forEach(System.out::println);
}
}
}
These queries address two common time-series scenarios: retrieving the latest observation for the account and obtaining its recent history, excluding the current record.
Using Jakarta Data
The same model can also be exposed through a Jakarta Data repository:
@Repository
public interface AccountTransactionRepository
extends BasicRepository<AccountTransaction, Instant> {
List<AccountTransaction> findByAccountOrderByIdDesc(
String account,
Limit limit);
}
The application code is now repository-oriented:
public class App2 {
public static void main(String[] args) {
var firstTransaction = new AccountTransaction(
Instant.parse("2026-09-20T08:00:00Z"),
"account-42",
new BigDecimal("79.90"),
"EUR",
TransactionStatus.APPROVED
);
var secondTransaction = new AccountTransaction(
Instant.parse("2026-09-20T09:00:00Z"),
"account-42",
new BigDecimal("24.50"),
"EUR",
TransactionStatus.APPROVED
);
var latestTransaction = new AccountTransaction(
Instant.parse("2026-09-20T10:15:00Z"),
"account-42",
new BigDecimal("120.00"),
"EUR",
TransactionStatus.DECLINED
);
try (SeContainer container =
SeContainerInitializer.newInstance().initialize()) {
AccountTransactionRepository repository =
container.select(AccountTransactionRepository.class).get();
repository.save(firstTransaction);
repository.save(secondTransaction);
repository.save(latestTransaction);
var currentStatus = repository
.findByAccountOrderByIdDesc(
"account-42",
Limit.of(1)
)
.stream()
.findFirst();
System.out.println(
"Current account status: " + currentStatus
);
var history = repository
.findByAccountOrderByIdDesc(
"account-42",
Limit.range(2, 10)
);
System.out.println("Recent transaction history:");
history.forEach(System.out::println);
}
}
}
Notably, the application expresses time-oriented business queries without relying directly on the InfluxDB client API. Familiar Java mapping and repository concepts are retained, while InfluxDB delivers specialized storage and query capabilities.
Where InfluxDB Fits in an Enterprise Architecture
While InfluxDB is commonly associated with monitoring or IoT use cases, its role in enterprise architecture is broader. It works best as a specialized time-series store that supplements, rather than replaces, other databases. Relational databases can continue to serve as systems of record for customers, orders, and transactions, while messaging platforms such as Kafka distribute events. InfluxDB then stores time-based operational metrics, telemetry, prices, business indicators, or application signals from these systems.
This separation simplifies the overall architecture. Transactional systems are designed for preserving consistency, relationships, and state changes, while time-series databases excel at handling continuous data, recent-state queries, historical ranges, and time-based aggregations. Combining both workloads in a single database may work initially, but as temporal data grows, it frequently leads to complex indexing, partitioning, and retention strategies.
For example, an e-commerce platform may store orders and payments in a relational database, while using InfluxDB for checkout latency, payment approval rates, inventory changes, and orders-per-minute. A financial platform can keep transactional records in its core database and use InfluxDB for exchange-rate history, portfolio measurements, or operational risk indicators. Similarly, an industrial platform might store machine metadata in a relational system and use InfluxDB for temperature, pressure, and vibration readings.
The architectural value lies in specialization. InfluxDB is most effective when applications need to answer questions like “what is happening now?”, “what changed during this period?”, or “how is this metric trending?” without placing all temporal responsibilities on the transactional database.
Conclusion
InfluxDB is a strong fit when applications need to work with continuously changing data, recent state, and historical context. With Eclipse JNoSQL 1.1.18, Java developers can use InfluxDB through familiar Jakarta APIs instead of depending directly on database-specific client code, making time-series workloads easier to integrate into modern enterprise applications.
Opinions expressed by DZone contributors are their own.
Comments