| name | database-per-service-example | ||||||
|---|---|---|---|---|---|---|---|
| description | Database-per-service sample that separates students and courses services into independent pluggable databases. | ||||||
| tags |
|
||||||
| blog_post |
This sample demonstrates the database-per-service pattern on Oracle AI Database with a realistic cross-service workflow: registration eligibility.
Each service owns its own pluggable database (PDB), schema, tables, and datasource:
students/: student profile and completed-course history instudentpdbcourses/: course catalog, prerequisites, and term offerings incoursepdbsample/: command-line runner and end-to-end test that compose data from both services over HTTP
The sample intentionally avoids cross-PDB joins, shared schemas, and database links. Eligibility is computed at the application layer after fetching service-owned data from each boundary.
Owns:
studentsstudent_completed_courses
Exposes:
POST /studentsPOST /students/{studentId}/completed-coursesGET /students/{studentId}GET /students/{studentId}/completed-coursesGET /db-info
Owns:
course_catalogcourse_prerequisitescourse_offerings
Exposes:
POST /coursesPOST /courses/{courseCode}/prerequisitesPOST /course-offeringsGET /courses/{courseCode}GET /courses/{courseCode}/prerequisitesGET /course-offerings/{courseCode}?termCode=...GET /db-info
Contains:
com.example.sample.DatabasePerServiceSampleRunner- the Testcontainers-backed end-to-end test
- the SQL*Plus script that provisions the PDBs and schema objects
- Oracle AI Database can isolate service-owned data at the PDB boundary
- two Spring Boot services can use different PDB service names in the same Oracle AI Database instance
- a realistic business decision can be composed without violating database ownership
The composed workflow is:
- Create a student profile in the
studentsservice - Add completed-course history in the
studentsservice - Create catalog and offering data in the
coursesservice - Read both service-owned datasets
- Compute registration eligibility in the sample runner
The decision uses:
- student status
- academic hold flag
- prerequisite completion
- offering availability
- seat availability
- Start an Oracle AI Database Free container.
- Run the setup script in
sample/src/test/resources/create-pdbs.sqlassysdba. - Start the
studentsservice. - Start the
coursesservice. - Run the sample runner.
The setup script creates:
studentpdbcoursepdbstudents_appcourses_app- the
studentsservice tables - the
coursesservice tables
Start the students service:
mvn -f database-per-service-example/pom.xml -pl students spring-boot:run \
-DJDBC_URL=jdbc:oracle:thin:@localhost:1521/studentpdb \
-DUSERNAME=students_app \
-DPASSWORD=testpwd \
-DSERVER_PORT=8081Start the courses service:
mvn -f database-per-service-example/pom.xml -pl courses spring-boot:run \
-DJDBC_URL=jdbc:oracle:thin:@localhost:1521/coursepdb \
-DUSERNAME=courses_app \
-DPASSWORD=testpwd \
-DSERVER_PORT=8082Run the sample runner:
mvn -f database-per-service-example/pom.xml -pl sample exec:java \
-DSTUDENTS_BASE_URL=http://localhost:8081 \
-DCOURSES_BASE_URL=http://localhost:8082The runner seeds an eligibility scenario, reads both services back, and prints a report showing the decision plus proof that the services are connected to different PDBs.
Run the module test suite with:
mvn -f database-per-service-example/pom.xml clean testThe end-to-end tests in sample/:
- start Oracle AI Database Free with Testcontainers
- provision
studentpdbandcoursepdb - boot both Spring Boot applications against separate PDBs
- seed data through service APIs
- verify eligible and ineligible scenarios
- assert both the business result and the PDB ownership boundaries
Because the tests create PDBs inside the Oracle container, repeated runs require enough local Docker disk space.