Spring JdbcTemplate change schema on every request - spring

I need to change schema name for every request. I am using SpringBoot JdbcTemplate as below:
jdbcTemplate.execute("set search_path = " + schemaName); //postgres
Few requests are successful and few are failing with table not found exception. When I checked in DB, schema and table exists. Somehow jdbcTemplate not able to perform request.
Is there any other way to change schema name on every request dynamically?
I am only using spring-boot-starter-data-jdbc. No jpa used/needed in project.

Related

Springboot 2.7.2 with Hibernate 5.6 Error ORA 32575 during INSERT

Using Springboot 2.7.2 and Hibernate 5.6 with Oracle 12.2 to write a web application. I use the repository model to do an insert and test with mockmvc. With SQL Debug turned on I get an error ORA 32575 at the point where it executes the insert statement. In the debug log it has INSERT INTO TABLE (COL1, COL2, ID) VALUES ('X','Y',DEFAULT). The Oracle error 32575 follows this. The ID field in question is part of a Hibernate pojo and is a primary key and uses GenerationType.SEQUENCE. It is an Entity that points to a Table.
The DataSource is "thin" driver using the ojdbc8.jar. The Datasource is set up using a #Configuration" annotation in the application during Tomcat startup. If you take all of this by itself I dont get the error above.
However, I have a requirement to connect to each database user through a PROXY USER account because we use Oracle Label Security. It looks something like GRANT CONNECT TO userX THROUGH proxyuser. Using the database driver it would be something like
Properties proxyProps = new Properties()
proxyProps.set(Connection.PROXY_USER_NAME, user)
oraCon.openProxySession(Connection.PROXYTYPE_USER_NAME)
This is being done inside of an application class called ProxyDelegatingDatasourceThin which extends DelegatingDataSource which is a Spring class that I believe gets called when a new connection attempt is made.
Again, queries work fine, updates seem to work, its only the INSERTS. The ID column itself is set to NUMBER and is flagged as a Primary Key. It is not set as any kind of an IDENTITY column.
The error seems to want the ID column to be omitted from the INSERT Statement all together but Hibernate or Spring is generating it with the DEFAULT in the VALUES that is associated to ID.
Im hoping someone can help. Spent days on this.
Set the #ID column to be nullable, insertable, updatable all set to false
Tried using merge and persist from the entity manager (EntityManager) instead of using the Spring Repository save() method.
The implicit caching property is set to true
The error seems to want the ID column to be omitted from the INSERT Statement all together but Hibernate or Spring is generating it with the DEFAULT in the VALUES that is associated to ID.
Adding more info...
When I remove the code above which opens the proxy session, I don't get the error. I also printed some info from the database context while using the proxy session and the PROXY USER is to the PROXY ACCOUNT and the SESSION user is to the user that is connecting through the PROXY ACCOUNT.
Whether I use the Oracle Thin Driver or UCP I get the same result.

Spring with Hibernate- how to pass schema name dynamically

I am using spring-Hibernate DAO Layer, i have created spring configuration file having data source and all the hbm xml list and each hbm is mapped with the table as
table ="schema1.table1"
We have another schema say prodSchema in production, i want to know how to pass schema name dynamically by using propfile etc.to the hbm file so that in runtime i can change.
Java annotation only supports compile time constants. i.e. you cannot put variable in annotation parameter.
REf : http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
Your situation is common to most of the project and developer. I generally use external database configuration file, where I put the connection parameters, schema and credentials. This file is created on each environment once and remains unchanged until there is any change in DB server.
General Hibernate Property for quick reference.
hibernate.connection.driver_class : JDBC driver class
hibernate.connection.url : JDBC URL (may contain schema)
hibernate.connection.username : database user
hibernate.connection.password : database user password
hibernate.default_schema : Qualify unqualified table names with the
given schema/tablespace in generated SQL. e.g. SCHEMA_NAME (use this
if you don't specify in JDBC URL)

Set default schema = SOMETHING in oracle using Spring Boot and Spring JDBC

I am working now with oracle and spring jdbc but I don't want to use the schema in my sql statements:
Example: Select * from SCHEMA.table
Is there any way to set default schema in application.properties or application.yml?
Assuming you define your database connections using spring datasources, you can set the default schema when defining the datasource configuration:
spring.datasource.schema = #value for your default schema to use in database
You can find more info here: Spring Boot Reference Guide. Appendix A. Common application properties
After doing some research, looks like Oracle driver doesn't let you set a default schema to work with, as noted here:
Default Schema in Oracle Connection URL
From that post, you have two options:
Execute this statement before executing your statements:
ALTER SESSION SET CURRENT_SCHEMA=yourSchema
Create synonyms for your tables/views/etc (which I find really cumbersome if we're talking about lots of elements in your database).
I would advice using the first option. From what I see, Spring boot doesn't offer a simple way to execute a statement when retrieving the connection, so the best bet will be to use an aspect around the getConnection method (or the method that retrieves the connection from the data source) and execute the statement there.
From your comment, an easier way to solve it is by using a script in spring.datasource.schema:
spring.datasource.schema = schema.sql
And then a file squema.sql with the following:
ALTER SESSION SET CURRENT_SCHEMA=mySchema
In spring boot, I've found another way of doing it,
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource(#Value("${spring.datasource.schema}") String schema) {
DataSource datasource = DataSourceBuilder.create().build();
if(!schema.isEmpty() && datasource instanceof org.apache.tomcat.jdbc.pool.DataSource){
((org.apache.tomcat.jdbc.pool.DataSource) datasource).setInitSQL("ALTER SESSION SET CURRENT_SCHEMA=" + schema);
}
return datasource;
}
I found another way to get around this by updating entity class with
#Table(schema = "SCHEMA_NAME" ,name = "TABLE_NAME")
If you are using hikari, use spring.datasource.hikari.schema=YOUR_SCHEMA.
Works for me with SpringBoot + tomcat using Oracle.
I was having issues with the currently accepted answer; specifically, the schema would only be changed from the initial connection. If your app uses a connection pool, you need to configure the pool to apply SQL for each connection.
For instance, using the default jdbc pool in Spring Boot 1.5.x (Tomcat):
spring.datasource.tomcat.init-s-q-l = ALTER SESSION SET CURRENT_SCHEMA=mySchema
Connecting to the database as your user, you can create a trigger that will change the schema each time you login:
CREATE OR REPLACE TRIGGER LOGON_TRG
AFTER LOGON ON SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = foo';
EXCEPTION
when others
then null;
END;
/
Another option is to create a datasource wrapper. Create the datasource as normal and then create the wrapper that forwards all methods except for the getConnection methods. For those I just added SQL to set the schema. We have multiple datasources and this allowed us to specify a different schema for each datasource. If anyone knows if there's an issue with this I'd love comments. Or if there's an alternative that uses the properties.

Disabling EclipseLink cache

In my application, when user logs in to the system the system reads some setting from DB and stores them on user's session. The system is performing this action by a JPA query using EclipseLink (JPA 2.0).
When I change some settings in DB, and sign in again, the query returns the previous results. It seems that EclipseLink is caching the results.
I have used this to correct this behavior but it does not work:
query.setHint(QueryHints.cache_usage,cacheUsage.no_cache);
If you want to set query hints, the docs recommend doing:
query.setHint("javax.persistence.cache.storeMode", "REFRESH");
You can alternately set the affected entity's #Cacheable annotation
#Cacheable(false)
public class EntityThatMustNotBeCached {
...
}
If you're returning a some kind of configuration entity and want to be sure that data is not stale, you can invoke em.refresh(yourEntity) after returning the entity from query. This will force the JPA provider to get fresh data from the database despite the cached one.
If you want to disable the L2 cache you can use <shared-cache-mode>NONE</shared-cache-mode> within <persistence-unit> in persistence.xml or use Cacheable(false) directly on your configuration entity.
If you're returning plain fields instead of entities and still getting stale data you may try clearing the PersistenceContext by invoking em.clear().

Jdbc Connection Pooling - using multiple schema known at runtime only

I am working on an engine that is doing the following:
gets data provider info from DB (that tells me to what database & schema details to connect to get my data)
use that info to connect to the database and get my data, that later I use to build some XML content.
The standard setup to handle and isolate database connection management would be to create a DataSource bean (I'm using Spring to wire my components) and inject that in my ProviderConfigDao (loads connection config) and ContentDao (loads data using connection details loaded previously). This would nicely isolate the handling of the connections from the actual code, thus the DAO classes not needing to know how and when a connection is created/opened/closed etc.
This setup doesn't work unfortunately, as when I create my connection, I need to be able to specify the database schema. I don't know all the different schemas from the beginning, so I can't create a set of DataSource objects to cover all of them, thus the DataSource object must be created at runtime and it's creation hidden from the users.
The only solution I can think of is:
Have another class/interface (DataSourceProvider) having one method:
//Gets the connection URL as parameter (which includes the schema name).
DataSource getDataSource(String url);
Add a bean in Spring config to provide a custom implementation for it that manages creation of DataSource objects for each schema.
Inject that object to my DAO classes instead of the DataSource object.
It's not a bad solution, but I was wondering if there is maybe support for something like this already in some open source package ... I'd rather use something already done and tested then reinvent the wheel.
Cheers,
Stef.
there's a JDBC Utils to get all the metada from a database org.springframework.jdbc.support.JdbcUtils
parameters:
DataSource
Implementation of org.springframework.jdbc.support.DatabaseMetaDataCallback

Resources