Mastering Data Management in Java Microservices: JPA, EJB, and Event‑Driven Architecture
This article explains how Java‑based microservices can keep data handling manageable by using domain‑driven design, separate data stores, hybrid persistence, event‑driven communication, JPA, EJB, Bean Validation, CDI, and various messaging protocols to achieve consistency and scalability.
Microservice‑Specific Data Characteristics
Identify data using a top‑down approach, model it at the business level, and store it in each microservice's own data store. The following sections describe how to recognize, process, and share this data across services.
Domain‑Driven Design Entities
Entity – defined by continuity and identity rather than attributes.
Value Object – immutable object containing attributes but no conceptual entity.
Aggregate – a collection of objects bound by a root entity (aggregate root) that enforces consistency.
Repository – provides methods to retrieve domain objects, allowing easy swapping of storage implementations.
These concepts map to your persistence layer and form the basis of logical and physical data models.
Each Microservice Has Its Own Data Store
Every microservice should own a separate database (see Figure 1). Sharing a database creates tight coupling, forces coordinated deployments, and hinders independent scaling.
Figure 1 Each Microservice Has Its Own Data Store
Relational databases can be isolated by:
One schema per service (Figure 2).
One database per service, possibly sharing the same DB server (Figure 2).
One database server per service – the highest isolation level (Figure 3).
Figure 2 One Schema per Service and One Database per Service
Figure 3 One Database Server per Service
Hybrid Persistence
Microservices may use different storage technologies (relational and NoSQL) within the same service. Structured data can stay in a relational DB, while unstructured, complex, or graph data can be stored in a NoSQL store.
Cross‑Microservice Data Sharing
When a user needs data from multiple services (e.g., payments and their status), an adapter service queries each service and aggregates the results, performing any necessary transformations.
Figure 4 Adapter Microservice
Event‑Driven Architecture
To maintain consistency across services without distributed transactions, use an event‑driven approach: the first service updates its store and publishes an event; the second service, subscribed to that event, updates its own store. This loosely couples services via publish/subscribe messages.
Final Consistency
During event processing, data may be temporarily inconsistent (e.g., an order is saved but payment not yet confirmed). Services must handle such eventual‑consistency scenarios, possibly sending user‑friendly retry messages.
Figure 5 Event Messages Between Microservices
Data Replication
Database replication can separate data stores but introduces coupling via schema changes and deployment coordination. Event‑based handling can avoid these pitfalls.
Event Sourcing and CQRS
Combine Command Query Responsibility Segregation (CQRS) with event sourcing: write operations (commands) modify state, while read operations query a separate model synchronized from the event store.
Figure 6 CQRS Example
Messaging Systems
Message‑oriented middleware (MOM) enables asynchronous communication across heterogeneous platforms. Common protocols include AMQP and MQTT.
Distributed Transactions
Most messaging systems support transactions, but distributed transactions across microservices should be avoided. Instead, rely on event‑driven patterns and compensating actions.
Java Support
Java provides many APIs to handle hybrid persistence, including JPA, EJB, CDI, Bean Validation, and JMS.
Java Persistence API (JPA)
JPA defines a standard way to map Java objects to relational databases. It offers CRUD methods via EntityManager (persist, find, merge, remove) and supports JPQL for complex queries.
Example 1 JPA Entity Class
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
@Temporal(TemporalType.DATE)
private Date orderDate;
// getters and setters …
}Example 2 Obtaining an EntityManager in Java SE
EntityManagerFactory emf = Persistence.createEntityManagerFactory("OrderDB");
EntityManager em = emf.createEntityManager();Example 3 Transaction Management in Java SE
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
em.persist(entity);
tx.commit();
} finally {
if (tx.isActive()) tx.rollback();
}Enterprise JavaBeans (EJB)
Stateless, stateful, singleton, and message‑driven beans provide container‑managed lifecycle, transactions, and security.
Example 14 Stateless No‑Interface EJB Using JPA
@Stateless
@LocalBean
public class OrderEJB {
@PersistenceContext
private EntityManager em;
public void addOrder(Order o) { em.persist(o); }
public void deleteOrder(Order o) { em.remove(o); }
}Example 15 Explicit Transaction Attributes
@TransactionAttribute(REQUIRED)
@Stateless
@LocalBean
public class OrderEJB {
@TransactionAttribute(REQUIRES_NEW)
public void methodA() { … }
@TransactionAttribute(REQUIRED)
public void methodB() { … }
}Bean Validation
Annotations such as @NotNull, @Size, and @Pattern enforce constraints on bean properties. Validation can be triggered automatically by the container or programmatically.
Example 17 Default Constraints
private String username; // @NotNull
@Pattern(regexp="\\(\\d{3}\\)\\d{3}-\\d{4}")
private String phoneNumber;
@Size(min=2, max=40)
private String briefMessage;Example 19 Programmatic Validation
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Order>> violations = validator.validate(order);Context and Dependency Injection (CDI)
CDI beans can replace EJBs when a lightweight container is desired, though they lack built‑in transaction management and security.
Java Message Service (JMS) API
JMS 2.0 simplifies sending and receiving messages. Use JMSContext and JMSProducer for producers, and message‑driven beans for consumers.
Example 22 Sending a Message to a Queue
@Stateless
@LocalBean
public class OrderEJB {
@Inject @JMSConnectionFactory("jms/myConnectionFactory")
JMSContext jmsContext;
@Resource(mappedName = "jms/PaymentQueue")
Queue queue;
public void sendMessage(String msg) {
jmsContext.createProducer().send(queue, msg);
}
}Example 23 Message‑Driven Bean Consumer
@MessageDriven(name="PaymentMDB", activationConfig={
@ActivationConfigProperty(propertyName="messagingType", propertyValue="javax.jms.MessageListener"),
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="PaymentQueue")
})
public class PaymentMDB implements MessageListener {
@TransactionAttribute(REQUIRED)
public void onMessage(Message m) {
if (m instanceof TextMessage) {
String text = ((TextMessage)m).getText();
// process …
}
}
}Example 24 Setting Correlation ID
JMSProducer producer = jmsContext.createProducer();
producer.setJMSCorrelationID(UUID.randomUUID().toString());
producer.send(queue, message);Example 25 Getting Correlation ID
String corrId = message.getJMSCorrelationID();Other Messaging Protocols
For non‑JMS systems, use native clients for MQTT, AMQP (RabbitMQ, Apache Qpid), or Apache Kafka. Spring provides integration libraries for these protocols.
Summary
This article demonstrated how Java‑based microservices can manage data effectively by giving each service its own store, leveraging JPA and EJB for persistence, applying domain‑driven design, using event‑driven architecture with JMS, and employing Bean Validation and CDI where appropriate.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
