Introduction
A Java application that works in development may fail in production because of:
- Missing indexes
- Poor schema design
- Connection pool exhaustion
- Large transactions
- N+1 queries
- Missing pagination
- Unoptimized SQL
- Excessive logging
- Improper caching
Production systems require much more than:
repository.save(entity);
A production-ready application requires:
✅ Proper schema design
✅ Connection pool tuning
✅ Monitoring
✅ Query optimization
✅ Caching
✅ Transaction management
✅ Deployment standards
This article concludes the Oracle and JPA series by focusing on production systems.
Enterprise Application Architecture
Client
↓
API Gateway
↓
Controller
↓
Service
↓
Repository
↓
JPA/Hibernate
↓
Connection Pool
↓
Oracle Database
Each layer should have a clear responsibility.
Schema Standards
Every table should follow consistent naming.
Tables
EMPLOYEE
ORDER_HEADER
ORDER_ITEM
Primary Keys
EMP_ID
ORDER_ID
Foreign Keys
DEPT_ID
CUSTOMER_ID
Constraints
PK_EMPLOYEE
FK_EMPLOYEE_DEPARTMENT
UK_EMPLOYEE_EMAIL
Recommended Audit Columns
Every business table:
CREATED_DATE TIMESTAMP NOT NULL
CREATED_BY VARCHAR2(50)
UPDATED_DATE TIMESTAMP
UPDATED_BY VARCHAR2(50)
VERSION NUMBER
Soft Delete
Avoid:
DELETE FROM EMPLOYEE;
Instead:
STATUS='INACTIVE'
or
IS_DELETED='Y'
Advantages:
- Auditability
- Recovery
- Historical reporting
Example
@Column(name = "IS_DELETED")
private String deleted;
Connection Pool Tuning
Spring Boot uses HikariCP.
Recommended Settings
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1800000
Pool Size Recommendations
| CPU Cores | Pool Size |
|---|---|
| 2 | 5 |
| 4 | 10 |
| 8 | 20 |
| 16 | 30 |
Large pools:
❌ More memory
❌ More context switching
❌ Reduced throughput
SQL Logging
Development:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.orm.jdbc.bind=TRACE
Production:
OFF
Avoid logging sensitive data.
Pagination
Bad:
repository.findAll();
Good:
PageRequest.of(0,20);
Generated SQL:
OFFSET 0 ROWS
FETCH NEXT 20 ROWS ONLY
DTO Projections
Avoid:
Employee entity
Return:
EmployeeSummaryDto
Advantages:
- Smaller payloads
- Faster serialization
- Less memory
Index Best Practices
Create indexes on:
✅ Primary keys
✅ Foreign keys
✅ Search columns
✅ Frequently filtered columns
Avoid indexes on:
❌ Frequently updated columns
❌ Low-selectivity columns
Example
Good:
CREATE INDEX IDX_EMP_EMAIL
ON EMPLOYEE(EMAIL);
Bad:
CREATE INDEX IDX_STATUS
ON EMPLOYEE(STATUS);
When only:
ACTIVE
INACTIVE
exist.
Composite Indexes
CREATE INDEX IDX_ORDER
ON ORDERS
(
CUSTOMER_ID,
STATUS
);
Best for:
WHERE CUSTOMER_ID=?
AND STATUS=?
Statistics
Oracle optimizer depends on statistics.
Gather:
EXEC DBMS_STATS.GATHER_TABLE_STATS(
USER,
'EMPLOYEE');
Explain Plan
Always analyze slow SQL.
EXPLAIN PLAN FOR
SELECT ...
Query Optimization Checklist
| Question | Recommendation |
|---|---|
| SELECT * used? | No |
| Index available? | Yes |
| Pagination used? | Yes |
| Full scan? | Avoid |
| Large joins? | Review |
Flyway
Database migrations.
Example:
V1__Create_employee.sql
V2__Add_index.sql
V3__Create_department.sql
Liquibase
XML/YAML migration approach.
Advantages:
- Version control
- Rollback
- Automated deployments
Never Use
ddl-auto=update
Production:
ddl-auto=validate
Batch Processing
hibernate.jdbc.batch_size=50
Benefits:
- Fewer round trips.
- Faster inserts.
Monitoring
Important metrics:
- Active connections
- Slow SQL
- Deadlocks
- Transaction duration
- Cache hit ratio
Oracle Views
V$SESSION
V$SQL
V$LOCK
V$TRANSACTION
Slow SQL Detection
Look for:
Elapsed Time
Buffer Gets
Disk Reads
AWR Reports
Automatic Workload Repository.
Provides:
- Top SQL
- Wait events
- CPU usage
- Memory usage
ASH Reports
Active Session History.
Useful for:
- Blocking sessions
- Performance issues
- Locking problems
Logging Best Practices
Log:
✅ Request IDs
✅ Transaction IDs
✅ Error codes
Avoid:
❌ Passwords
❌ Personal data
❌ Large payloads
Exception Handling
Map:
| Exception | HTTP |
|---|---|
| EntityNotFound | 404 |
| Validation | 400 |
| Duplicate Key | 409 |
| Unexpected | 500 |
Caching Strategy
| Data | Cache |
|---|---|
| Reference Data | Yes |
| Configuration | Yes |
| Reports | Yes |
| Transactions | No |
Redis Use Cases
- Master data
- Country lists
- Product catalogs
- Configuration
Second-Level Cache
Useful for:
- Read-heavy systems
- Lookup tables
Avoid for:
- Frequently updated entities
API Design
Avoid:
Employee Entity
Return:
EmployeeResponse
Benefits:
- Versioning
- Security
- Smaller payloads
Security Best Practices
✅ Dedicated DB users
✅ Password rotation
✅ Least privilege
✅ Separate schemas
✅ Auditing
Production Checklist
Database
✅ Indexes
✅ Statistics
✅ Constraints
✅ Audit columns
JPA
✅ LAZY loading
✅ DTOs
✅ Pagination
✅ Version column
Transactions
✅ Short transactions
✅ Timeouts
✅ Optimistic locking
Operations
✅ Monitoring
✅ Alerting
✅ Logging
Example Enterprise Table
EMPLOYEE
---------
EMP_ID
NAME
EMAIL
STATUS
CREATED_DATE
CREATED_BY
UPDATED_DATE
UPDATED_BY
VERSION
Common Production Problems
| Problem | Root Cause |
|---|---|
| Slow APIs | N+1 |
| High DB CPU | Missing indexes |
| Connection exhaustion | Leaks |
| Deadlocks | Long transactions |
| Memory issues | Large result sets |
| Slow startup | EAGER loading |
Enterprise Recommendations
OLTP Systems
- Small transactions
- Optimistic locking
- Pagination
Reporting Systems
- Read-only transactions
- DTOs
- Batch processing
Microservices
- UUID keys
- DTO APIs
- Event-driven integration
Banking Systems
- Sequence keys
- Pessimistic locking
- Strong auditing
Interview Questions
Why avoid ddl-auto=update?
Uncontrolled schema changes.
Why use pagination?
Reduce memory and SQL load.
Why use DTOs?
Smaller object graphs.
Why gather statistics?
Optimizer decisions.
What causes pool exhaustion?
Connection leaks.
Why use audit columns?
Tracking changes.
Complete Series Summary
| Part | Topic |
|---|---|
| Part 1 | Oracle Fundamentals and Schema Design |
| Part 2 | Users, Roles and Security |
| Part 3 | SQL and Query Optimization |
| Part 4 | JDBC Connectivity |
| Part 5 | JPA and Hibernate |
| Part 6 | Relationships and Joins |
| Part 7 | Composite Keys |
| Part 8 | Lazy Loading and Performance |
| Part 9 | Transactions and Locking |
| Part 10 | Production Best Practices |
Final Recommendations for Java Developers
Database Design
✅ Use meaningful datatypes.
✅ Add constraints.
✅ Keep schemas normalized.
JPA
✅ Prefer LAZY.
✅ Use DTOs.
✅ Add version columns.
Performance
✅ Use indexes.
✅ Use pagination.
✅ Avoid N+1 queries.
Transactions
✅ Keep them short.
✅ Use optimistic locking.
Production
✅ Monitor everything.
✅ Version database changes.
✅ Separate environments.
Conclusion
Oracle, JPA, and Hibernate are powerful technologies, but performance and maintainability depend more on design decisions than frameworks.
A strong backend developer understands:
- Data modeling
- SQL optimization
- Transaction management
- JPA performance
- Database operations
- Production troubleshooting
Those skills remain valuable regardless of the framework or architecture used in future applications.