Re-establishing connections in Oracle UCP pool - oracle

I am using Oracle UCP JDBC, and the following method is for getting a connection from a connection pool.
private static PoolDataSource poolDataSource;
....
static synchronized Connection createConnection() throws SQLException {
if (poolDataSource == null) {
poolDataSource = PoolDataSourceFactory.getPoolDataSource();
poolDataSource.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
poolDataSource.setURL(url);
poolDataSource.setUser(user);
poolDataSource.setPassword(password);
poolDataSource.setInitialPoolSize(1);
poolDataSource.setMinPoolSize(1);
poolDataSource.setMaxPoolSize(10);
}
Connection connection = poolDataSource.getConnection();
return connection;
}
I know that there is Connection.isValid() method to check whether a connection obtained from the pool is valid. But if isValid() returns false, what can I do? How do I force the connection pool to re-establish its connection?
Also, note that in our test environment, we are not using RAC (Real Application Clusters), but in production environment, we do have RAC. I have read that for RAC, we need to do some configuration in the codes in order for RAC to work.
Is it possible to have the same codes for RAC and non-RAC environments so that invalid connections in the pool re-established?
Thanks in advance.

If your database is up and running then isValid() will return true indicating that app can connect to the DB. However, in the production system, there will be many nodes and if one of the nodes is down then UCP will get the connection from other nodes. Let me know if this clarifies your question.

Related

UCP Connection pool cannot create connection after a database network error

I have a problem with the Oracle Universal Connection Pool (UCP) implemented in a Scala application, for an Oracle Database.
It works perfectly while there's a connection to the database, but when the network has some problem for a limited period of time (the application or the database goes offline) it obviously fails to create a Connection while the problem persists, but then it doesn't manage to create new ones when the application can ping the database again. The only way to get the application work again is to restart it.
I've set up a class in which I manage the connection, and I create the pool data source with this method:
private def createConnectionPool(
connectionString: String,
username: String,
password: String
): PoolDataSource =
{
val p = PoolDataSourceFactory.getPoolDataSource()
p.setConnectionPoolName("main_ucp_pool")
p.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource")
p.setURL(connectionString)
p.setUser(username)
p.setPassword(password)
p.setInitialPoolSize(5)
p.setMinPoolSize(3)
p.setMaxPoolSize(20)
p
}
private lazy val pds = createConnectionPool('url', 'username', 'pass')
Then, every time I need a database connection, I get it through this method invocation:
pds.getConnection()
Am I missing something in the code, or is it true that the pool data source should retry to establish a connection to the database when the getConnection method is invoked, even after a network problem?
In other words, if it fails to create the connection when the network goes down, the second time, if the application can now ping the database, the connection must be established?

DB connections increase after setting aurora in MariaDB connector

We're testing the failover behaviour using the MariaDB JDBC connector Aurora specific features.
We've set the JDBC URL as the documentation suggest:
jdbc:mysql:aurora://cluster.cluster-xxxx.us-east-1.rds.amazonaws.com/db
The problem is that as soon as we add the aurora: part in the URL schema, we can see an increase in the connections to the database writer until the point that we've to rollback the change (it even reaches 3.000 connections).
Versions:
MariaDB connector: 2.0.1
HikariCP connection pool: 2.6.1
Play-Slick: 2.1.0
Slick: 3.2.0
Configuration:
master {
profile = "slick.jdbc.MySQLProfile$"
db {
driver = "org.mariadb.jdbc.Driver"
url = "jdbc:mysql:aurora://cluster-name.cluster-xxx.us-east-1.rds.amazonaws.com/db_name?characterEncoding=utf8mb4&rewriteBatchedStatements=true&usePipelineAuth=false"
user = "rw_user"
password = "rw_user_pass"
numThreads = 20
queueSize = 1000000
}
}
slaves = [
{
profile = "slick.jdbc.MySQLProfile$"
db {
driver = "org.mariadb.jdbc.Driver"
url = "jdbc:mysql:aurora://cluster-name.cluster-ro-xxx.us-east-1.rds.amazonaws.com/db_name?characterEncoding=utf8mb4&usePipelineAuth=false"
user = "ro_user"
password = "ro_user_pass"
numThreads = 20
queueSize = 1000000
}
}
]
We'd tried to add the aurora: part to the JDBC URL schema after upgrading the MariaDB connector version, but the number of connections to the Reader started to increase again:
If we run a show processlist on the read only endpoint, we can see all the opened connections in "cleaned up" state, and "Sleep" command.
We'd removed the aurora: part from the read only endpoint just in order to stabilize the number of connections to it. Is it possible that the driver searches for the cluster master while opening connections? That would explain this kind of behaviour.
When using the "aurora" keyword, driver , under the hood, create 2 connections:
a connection to the primary server,
a connection to one of the replicas if any.
The goal is always to save resources on the main server. Generally, only one pool is configured. The driver then uses the connection to the primary / replica according to [Connection.setReadOnly] [1].
When you have separate "write" / "read" pools, using the configuration "failover" will solve your issue: Driver will use only one real connection.
This way, there will be no "wasted" connection.
Failover will then be handled differently, but with the same results (for example, a query not in a transaction that is to be sent to a replica that just crashed will not directly use the primary connection as when using the "aurora" configuration, the driver will recreate a new connection to another replicas before executing the query).
Once you get past several dozen active connections, the database starts stumbling over itself. It is better to throttle the connections in the client instead of assuming you have infinite bandwidth to accept connections in Aurora.

Unable to enlist a distributed transaction after database restart

Hi I have problem with enlist to distributed transaction after database restart.
My environment:
Windows 7 x64 with SP1
Oracle Database 11g Express Edition
ODP.NET 4.112.3.0
My program:
const string connectionString = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=LOCALHOST)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=system;Password=sasa;";
static void Main(string[] args)
{
using (TransactionScope scope = new TransactionScope())
{
while (true)
{
using (OracleConnection connection = new OracleConnection(connectionString))
{
try
{
connection.Open();
Console.WriteLine("Connection opened");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Thread.Sleep(1000);
}
}
}
All works great after application start. When I start stopping database I get NRE and some exception telling me that database shutdown is in progress. After start it again i'm receiving error - Unable to enlist in a distributed transaction. Connection opened is no longer printed.
Output:
Connection opened
Connection opened
Connection opened
Connection opened
Connection opened
-- here I'm stopping database
ORA-12518: TNS:listener could not hand off client connection
ORA-12528: TNS:listener: all appropriate instances are blocking new connections
-- here database is stopped I suppose
ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
-- here I'm starting database again
ORA-12528: TNS:listener: all appropriate instances are blocking new connections
ORA-1033: ORACLE initialization or shutdown in progress
Unable to enlist in a distributed transaction
Unable to enlist in a distributed transaction
Unable to enlist in a distributed transaction
Unable to enlist in a distributed transaction
Unable to enlist in a distributed transaction
...
What is the reason of that behavior?
How to diagnose what's happen?
You have an invalid test. You are looping inside the context of a single transaction. When the database goes down any in-progress distributed transaction is aborted. Your loop is trying to bring up a new connection under that already-dead transaction.
I'm not sure exactly what you are trying to test but moving the TransactionScope inside of the while loop should fix it.

How to know if an OracleConnection coming from the connection pool was used before

My application needs to authenticate all session on the DB via a trusted procedure (that sets some values in the session context). Currently this procedure is called for each new session just after it is opened.
I'd now like to improve this by removing unneeded round-trips. Connections from the connection pool which were used (and authenticated) before don't need to call the procedure again because the session context variables are still set on the server.
But I can't find a way to identify reused connections. Is there any way (which of course doesn't need a round-trip too)?
Architecture: Multiple client applications use the same DB account (a read-only account with synonyms to the real schema) to connect. After the connection it is required that each new session calls an authentication procedure to set some session context variables. These context variables are checked on select/insert/update/delete by Oracle FGAC (virtual private database).
My code:
OracleConnection conn = new OracleConnection();
conn.ConnectionString = _connectionString;
conn.Open();
if (true) { // TODO: Identify not yet authenticated connections.
using (OracleCommand cmd = new OracleCommand("authentication.login", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("i_user_id", OracleDbType.Int64).Value = _userId;
cmd.Parameters.Add("i_role_id", OracleDbType.Int64).Value = _roleId;
cmd.ExecuteNonQuery();
}
}
You could create a connection pool for your oracle connections.
And each connection you create could be inserted with a some key (using conn.setSessionInfo(key)) that can be verified later when you get the connection back.
The key can be a any thing of your choice or maybe a hashkey you generate.
I finally found an answer that clearly states that this isn't possible: ODP.NET connection pooling: How to tell if a connection has been used
You should clear all contexts and reset all packages anyway when you get a connection from a connectionpool. Add this authentication to your initialization.
Preparing an Oracle Connection after being retrieved from a ConnectionPool
I'm not clear what your authentication is doing - verifying that the connection comes from your app? - and whether you're passing anything to your procedure. Could you consider using a logon trigger to call your procedure from the DB side, only for the user your pool is using, as the session is created?

ADO.NET for oracle doesn't close connections

When connecting to oracle server from .NET application using ADO.NET for oracle, even if i closed the connection, the connection remains inactive at the Oracle server, so new connections could not be established because of the sessions per user limitation, is there is any way to make sure that all connections are closed? from Oracle server or from .NET application.
Thanks in advance
Could it be the connections stay open for a while due to connection pooling? Can you please paste some code showing how you close the connections? Also are you using ODP.NET or the Microsoft supplied classes?
You could try turning connection pooling off (add ;Pooling=false to the connection string in ODP.NET) to see if your issue is caused as a consequence of using it (just be aware that creating a new physical connection to the DB is an expensive operation, so you probably actually don't want to turn off connection pooling permantly).
Something similar to:
using (OracleConnection connection = new OracleConnection(connectionString))
{
OracleCommand command = new OracleCommand(queryString);
command.Connection = connection;
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Resources