Database Documentation
1. Database
This section provides detailed information about the database architecture, configuration, and best practices for the Northbound API.
1.1. Database Overview
The application uses a multi-database architecture to interact with different data sources. The ACS backend can be served by either MySQL or Oracle depending on deployment requirements.
-
ACS Database: Stores devices data including configurations, provisioning templates, and service definitions.
1.2. Database Configuration
1.2.1. Data Source Configuration
The application configures multiple data sources through Spring Boot properties. Each data source is configured with its own connection pool using HikariCP.
spring:
datasource:
acs:
jdbc-url: ${MYSQL_JDBC_URL:jdbc:mysql://${MYSQL_HOST:${DB_HOST:localhost}}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:ftacs}?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC}
username: ${MYSQL_USER:${DB_USERNAME:ftacs}}
password: ${MYSQL_PASSWORD:ftacs}
driver-class-name: ${MYSQL_DRIVER_CLASS_NAME:com.mysql.cj.jdbc.Driver}
maximum-pool-size: ${DB_MAX_POOL_SIZE:10}
minimum-idle: ${DB_MIN_IDLE:5}
connection-timeout: ${DB_CONNECTION_TIMEOUT_MS:30000}
Configure the host, schema, and credentials through MYSQL_HOST, MYSQL_SCHEMA, MYSQL_USER, and MYSQL_PASSWORD, or override the entire string with MYSQL_JDBC_URL when you need extra connection parameters.
The Oracle distribution mirrors these properties under application-oracle.yml, exposing ORACLE_HOST, ORACLE_SERVICE, ORACLE_USER, and ORACLE_JDBC_URL alongside the oracle.jdbc.OracleDriver.
1.2.2. JPA Configuration
Each database has its own EntityManagerFactory and TransactionManager configuration.
ACS Configuration
package com.friendly.northboundapi.config.db;
import com.friendly.apicommon.db.DatabaseType;
import com.friendly.apicommon.db.DbConfig;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.EntityManagerFactory;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import java.util.HashMap;
@DependsOn("dbConfig")
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
@Configuration
@EnableJpaRepositories(
basePackages = {"com.friendly"},
entityManagerFactoryRef = "acsEntityManager",
transactionManagerRef = "acsTransactionManager",
includeFilters = @ComponentScan.Filter(
type = FilterType.CUSTOM,
classes = AcsSchemaFilter.class)
)
@Slf4j
@RequiredArgsConstructor
public class JpaAcsConfig {
@NonNull
private final Environment env;
@Bean
@ConfigurationProperties(prefix = "spring.datasource.acs")
public HikariDataSource acsDataSource() {
HikariDataSource ds = new HikariDataSource();
if (DbConfig.getDbType().equals(DatabaseType.Oracle)) {
ds.setConnectionInitSql("ALTER SESSION SET TIME_ZONE='UTC'");
}
return ds;
}
@Bean
public FactoryBean<EntityManagerFactory> acsEntityManager() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(acsDataSource());
em.setPackagesToScan("com.friendly");
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
properties.put("hibernate.dialect", DbConfig.getDbType().equals(DatabaseType.Oracle)
? env.getProperty("oracle.dialect") : env.getProperty("mysql.dialect"));
properties.put("hibernate.enable_lazy_load_no_trans",
env.getProperty("spring.jpa.properties.hibernate.enable_lazy_load_no_trans", "true"));
properties.put("jpa.open-in-view", env.getProperty("spring.jpa.open-in-view", "true"));
if (DbConfig.getDbType().equals(DatabaseType.Oracle)) {
properties.put("hibernate.jdbc.time_zone", "UTC");
}
em.setJpaPropertyMap(properties);
log.info("ACS DB properties: {}", properties);
return em;
}
@Bean
public PlatformTransactionManager acsTransactionManager(
@Qualifier("acsEntityManager") EntityManagerFactory entityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManager);
return transactionManager;
}
}
1.3. Database Schema
1.3.1. ACS Schema
The ACS schema contains tables used by the Northbound API for device management, provisioning, and operations. The schema must already exist before deploying the Northbound API — the application does not create or migrate tables.
Device Core
| Table | Purpose |
|---|---|
|
Device records (serial number, manufacturer, model, OUI, connection status) |
|
Device serial number mappings |
|
Custom device fields (user-defined attributes) |
|
Domains (ISP/location hierarchy) |
|
Device model definitions |
|
Device model groupings |
|
Manufacturer records |
Device Parameters & Methods
| Table | Purpose |
|---|---|
|
Device parameter values |
|
Parameter name definitions |
|
Device method definitions |
|
Method name definitions |
Tasks & Transactions
| Table | Purpose |
|---|---|
|
Tasks waiting to be executed on devices |
|
Successfully completed tasks |
|
Tasks that failed execution |
|
Tasks rejected by the device |
|
Transaction tracking for async operations |
Provisioning
| Table | Purpose |
|---|---|
|
Device provisioning definitions |
|
Provisioned object tree structures |
|
Parameters within provisioned objects |
|
Files associated with device provisioning |
Device Operations
| Table | Purpose |
|---|---|
|
Custom RPC method definitions |
|
Custom RPC execution history |
|
Device diagnostic sessions |
|
Device activity history |
|
Device blacklist entries |
|
Detailed device activity records |
|
FTP file management records |
1.4. Best Practices
1.4.1. Database Access
-
Repository Pattern: Use Spring Data JPA repositories for database access
-
Transaction Management: Use
@Transactionalannotation with appropriate transaction manager -
Entity Relationships: Define relationships with appropriate fetch strategies
-
Pagination: Use paging and sorting repositories for large data sets
1.4.2. Performance Considerations
-
Connection Pooling: Configure appropriate pool sizes based on load
-
Query Optimization: Use indexed fields for filtering and sorting
-
Batch Operations: Use batch inserts and updates for bulk operations
-
Caching: Utilize caching for frequently accessed, rarely changing data