Oracle Real Application Clusters (RAC) introduces the concept of Single Client Access Name (SCAN), which allows client applications to connect to the database using a single hostname instead of individual node VIPs. SCAN simplifies client configuration while enabling load balancing and failover across RAC nodes.
Why Test SCAN Load Balancing?
Validating SCAN behavior ensures applications fully leverage RAC capabilities without hardcoding node details.
- Ensure JDBC connections are distributed across RAC instances
- Verify transparent failover during node outages
- Understand how applications interact with RAC services
Prerequisites
Before testing Oracle SCAN load balancing with Java, ensure the following prerequisites are met to avoid connectivity or configuration issues.
- Oracle RAC Environment: A properly configured Oracle RAC cluster with SCAN listeners running.
-
SCAN DNS Resolution:
SCAN name must resolve to multiple IP addresses.
nslookup pbidcrpl-scan1.pbi.com
- RAC Service: Service must be created using srvctl and running on all RAC nodes.
- Network Access: Client host must be able to reach SCAN listeners on port 1522.
- Java Development Kit: Oracle JDK 8 or higher (JDK 19 used in this test).
- Oracle JDBC Driver: Compatible Oracle JDBC Thin driver (ojdbc8.jar or newer).
- Database User: A valid database user with connect privilege on the RAC service.
Incorrect SCAN DNS or service configuration may result in all connections landing on a single instance. Always validate SCAN resolution before testing.
Test Environment
- Oracle Database: 19c Enterprise Edition (19.26.0)
- RAC Nodes: pbidcdbadm01, pbidcdbadm02
- Service Name: pbifincr
- SCAN Name: pbidcrpl-scan1.pbi.com:1522
- JDBC Driver: Oracle JDBC 23.26
- Java Version: Oracle JDK 19
Java Program for SCAN Load Balancing Test
The Java program below opens multiple JDBC connections using the SCAN address and prints the instance name, host, and service serving each connection.
import java.sql.*;
import java.util.Date;
import oracle.jdbc.pool.OracleDataSource;
public class LoadBalanceTestSCAN {
private OracleDataSource ods;
private static final String url =
"jdbc:oracle:thin:@pbidcrpl-scan1.pbi.com:1522/pbifincr";
public LoadBalanceTestSCAN() throws SQLException {
ods = new OracleDataSource();
ods.setUser("dbsnmp");
ods.setPassword("welcome1");
ods.setURL(url);
}
public Connection getConnection() throws SQLException {
return ods.getConnection();
}
public void run() throws SQLException {
Connection[] conns = new Connection[5];
for (int i = 0; i < conns.length; i++) {
conns[i] = getConnection();
}
for (int i = 0; i < conns.length; i++) {
printInstanceDetails(conns[i], i);
}
for (Connection c : conns) {
c.close();
}
}
private void printInstanceDetails(Connection conn, int i) throws SQLException {
String sql =
"select sys_context('userenv','instance_name'), " +
"sys_context('userenv','server_host'), " +
"sys_context('userenv','service_name') from dual";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println("Connection #" + i +
" Instance=" + rs.getString(1) +
" Host=" + rs.getString(2) +
" Service=" + rs.getString(3));
}
rs.close();
stmt.close();
}
public static void main(String[] args) throws Exception {
System.out.println("Test Started at " + new Date());
new LoadBalanceTestSCAN().run();
System.out.println("Test Ended at " + new Date());
}
}
Compile The Java Class Program
$ORACLE_HOME/jdk/bin/javac -cp ojdbc8.jar LoadBalanceTestSCAN.java
Run The Java Program
$ORACLE_HOME/jdk/bin/java -cp .:ojdbc8.jar LoadBalanceTestSCAN
Output of The Java Program
Test Started at Wed Dec 10 17:41:19 IST 2025 Obtaining 5 connections using URL : jdbc:oracle:thin:@pbidcrpl-scan1.pbi.com:1522/pbifincr ============= Database Product Name is ... Oracle Database Product Version is Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.26.0.0.0 ============= JDBC Driver Name is ........ Oracle JDBC driver JDBC Driver Version is ..... 23.26.0.0.0 JDBC Driver Major Version is 23 JDBC Driver Minor Version is 26 ============= Connection #0 : instance[pbifincr1], host[pbidcdbadm01], service[pbifincr] Connection #1 : instance[pbifincr1], host[pbidcdbadm01], service[pbifincr] Connection #2 : instance[pbifincr2], host[pbidcdbadm02], service[pbifincr] Connection #3 : instance[pbifincr2], host[pbidcdbadm02], service[pbifincr] Connection #4 : instance[pbifincr1], host[pbidcdbadm01], service[pbifincr] Closing Connections Test Ended at Wed Dec 10 17:44:42 IST 2025
Observations
- Connections are established using SCAN instead of node VIPs
- Sessions are distributed across RAC instances
- Higher concurrency improves visible load balancing
Best Practices
- Always use SCAN in JDBC URLs
- Configure services with appropriate load balancing goals
- Test with realistic connection volumes
- Monitor using GV$SESSION or ASH views
For production environments, validate failover by stopping RAC instances and test using connection pools such as UCP.
Conclusion
Testing Oracle SCAN load balancing with Java provides a reliable way to validate RAC connectivity, load distribution, and high availability. This simple test can be reused in QA pipelines to ensure application resilience.
Please feel free to ask. Thank you 🙂
Toufique Khan
