Clean • Professional
The Database per Service Pattern is one of the most critical and non-negotiable principles of microservices architecture.
It ensures loose coupling, scalability, autonomy, fault isolation, and clear data ownership by allowing each microservice to manage its own database.
In a true microservices system:
👉 If microservices share a database, they are not real microservices — they become a distributed monolith.
In microservices architecture, each microservice owns its database, and only that service can read or write to it.
One Microservice = One Database (or schema) it fully controls

This rule:
Each microservice represents a business capability, not just a technical module.
To stay independent, it must own its data completely.
Independent Development
Independent Deployment
Independent Scaling
Clear Data Ownership
Without database ownership, microservices lose their purpose.
Sharing a database between microservices is one of the most dangerous anti-patterns.
Shared Database Between Services
User Service ─┐
├── SharedDatabase
Order Service ─┘
Problems with Shared Databases:

📌 Shared Database = Distributed Monolith
Even if services are deployed separately, a shared database makes them tightly coupled.
Loose Coupling
Independent Scaling
Technology Flexibility
Fault Isolation
Clear Boundaries
E-Commerce Microservices System
| Microservice | Responsibility | Database |
|---|---|---|
| User Service | Users & profiles | MySQL |
| Order Service | Orders & items | PostgreSQL |
| Payment Service | Payments | MongoDB |
| Inventory Service | Stock | Redis |
Each service:
Microservices never query each other’s databases.
1. REST / gRPC (Synchronous)
GET <http://user-service/users/{id}>
2. Event-Driven Communication (Recommended)
User Service publishes:
UserCreatedEventUserUpdatedEventOrder Service:
✔ Loose coupling
✔ High scalability
✔ Better resilience
✔ Eventual consistency
📌 Data is shared by communication, not by database access.
Entity
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
Controller
@RestController
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@PostMapping
public User createUser(@RequestBody User user) {
return userRepository.save(user);
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id).orElseThrow();
}
}
📌 User Service accesses only User DB.
Entity
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private Double amount;
}
Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}
Controller
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderRepository orderRepository;
public OrderController(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@PostMapping
public Order createOrder(@RequestBody Order order) {
return orderRepository.save(order);
}
}
📌 Order Service never accesses User DB.
Since each service has its own database, traditional distributed transactions are avoided.
Common Challenges:
📌 Microservices rely on eventual consistency, not immediate consistency.
The Saga Pattern manages transactions across multiple microservices.
How Saga Works:
Example:

📌 In these cases, a monolith with a single database is better.
Companies using Database per Service Pattern:
The Database per Service Pattern is a foundational principle of microservices.
No microservice should ever directly access another microservice’s database.