Jdbc Connection Pooling - using multiple schema known at runtime only - jdbc

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

Related

How to set properties of Tomcat JDBC Pool when using Spring Cloud Connector config?

I want to configure the properties of the Tomcat JDBC Pool with custom parameter values. The pool is bootstrapped by the spring-cloud (Spring Cloud Connector) environment (Cloud Foundry) and connected to a PostgreSQL database. In particular, I want to set the minIdle, maxIdle and initialSize properties for the given pool.
In a "spring-vanilla" environment (non-cloud) the properties can be easily set by using
application.properties / .yaml files with environment properties,
#ConfigurationProperties annotation.
However, this approach doesn't transfer to my Cloud environment, where the URL (and other parameters) are injected from the environment variable VCAP_SERVICES (via the ServiceInfo instances). I don't want to re-implement the logic which Spring Cloud already did with its connectors.
After some searching I also stumbled over some tutorials / guides, which suggest to make use of the PoolConfig object (e.g. http://cloud.spring.io/spring-cloud-connectors/spring-cloud-spring-service-connector.html#_relational_database_db2_mysql_oracle_postgresql_sql_server). However, that way one cannot set the properties I need but merely the following three:
minPoolSize,
maxPoolSize,
maxWaitTime.
Note that I don't want to set connection-related properties (such as charset), but the properties are associated with the pool itself.
In essence, I would like to do the configuration similarly to https://www.baeldung.com/spring-boot-tomcat-connection-pool (using spring.datasource.tomcat.* properties). The problem with that approach is that the properties are not considered if the datasource was created by Spring Cloud. The article https://dzone.com/articles/binding-data-services-spring, section "Using a CloudFactory to create a DataSource", claims that the following code snippet makes it so that the configuration "can be tweaked using application.properties via spring.datasource.* properties":
#Bean
#ConfigurationProperties(DataSourceProperties.PREFIX)
public DataSource dataSource() {
return cloud().getSingletonServiceConnector(DataSource.class, null);
}
However, my own local test (with spring-cloud:Greenwich.RELEASE and spring-boot-starter-parent:2.1.3.RELEASE) showed that those property values are simply ignored.
I found an ugly way to solve my problem but I think it's not appropriate:
Let spring-cloud create the DataSource, which is not the pooled DataSource directly,
check that the reference is a descendant of a DelegatingDataSource,
resolve the delegate, which is then the pool itself,
change the properties programmatically directly at the pool itself.
I do not believe that this is the right way as I am using internal knowledge (on the layering of datasources). Additionally, this approach does not work for the property initialSize, which is only considered when the pool is created.

Is it possible to get the SQL query causing a Spring DataAccessException?

I have an application that uses a JdbcTemplate to perform queries on a MySQL database. If the JdbcTemplate ever throws an org.springframework.dao.DataAccessException, it logs the exception's stack trace. However, I'd also like to include the SQL query that caused the exception to be thrown. Is there an easy way to do this that doesn't involve writing custom error messages for every place JdbcTemplate is used?
If you only intend to log SQL statements during an exception, you might have to write your own custom subclass of JdbcTemplate and alter the logging preconditions as seen in the source code at Github.
If that is not the case, you may consider the following.
From the Spring documentation, All SQL Statements are logged at DEBUG level.
All SQL issued by this class is logged at the DEBUG level under the category corresponding to the fully qualified class name of the template instance (typically JdbcTemplate, but it may be different if you are using a custom subclass of the JdbcTemplate class).
You make also change the Jdbc url by setting profileSQL to true to trace the SQL.
MySQl Connection Reference Documentation

dynamically setting DataSource properties for Spring jdbc

I'm using spring jdbc and I want my application to connect to different DBMS as oracle,mySQL, SAS etc.
the application should work on different systems, so the connection properties are not priorly known.
Ideally, the user will be able to select connection type from a list and then set the connection properties (username,password...)
Can you please help me :)
Have a look at this post: http://examples.javacodegeeks.com/enterprise-java/spring/jdbc/spring-jdbctemplate-example/
There you can see the normal jdbctemplate use. As you can see the dao has got the datasource injected: you can basically do the same, but you need not to set the org.springframework.jdbc.datasource.DriverManagerDataSource properties in the applicationContext.xml. You will do it at runtime according to user choice. That basically means all the daos have to get the datasource needed params in input.
Hope this helps.

Spring annotation based configuration change

I have a spring MVC (3.1) web app using Hibernate that is all working correctly - today, I have tried to move the configuration completely over to annotation based config (only using xml for the security stuff that isnt yet supported by Spring in code config).
After some tuning I got the app starting with no errors and the home page loads correctly - however I am seeing some different behaviour with the Hibernate sessions - namely, I am getting the following error when loading a page that actually touches Hibernate entities:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.tmm.web.domain.Profile.connections, no session or session was closed
This is happening in the following scenario:
a request hits my #Controller and it loads the user Profile object
In the same method call (so we are not talking detached entities etc here) it tries to call profile.getConnections()
Profile.connections do not actually explicitly state a fetchtype, so should default to eager load (is my understanding?), but either way, the getConnections() call is directly after the loading of the profile - so would have thought even if it was being loaded lazily, it could easily just go back to the DB and load connections on demand.
//#Controller Code
Account viewedUser = accountService.loadAccountByUserName(userName);
model.put("viewedUserConnections", viewedUser.getUserProfile().getConnections());
//Profile Entity
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List connections = new ArrayList();
Now, I know about lazy loading etc, so it's not a question about that - like i mentioned all the Hibernate stuff was working correctly - so really my question is, what Spring configuration might affect this behaviour?
I can post my before and after xml vs annotation config, but am hoping that someone can point me in the direction of some config that I might have missed in switching.
Your assumptions are mainly wrong:
In the same method call (so we are not talking detached entities etc here)
The method is a method of the controller. In typical Spring applications, controllers are not transactional, but services are. So, unless you configured an "open session in view" filter or interceptor, the session is closed when the transactional service method returns, and the controller thus always uses detached entities
Profile.connections do not actually explicitly state a fetchtype, so should default to eager load
No. XxxToMany associations are lazy by default.
If the same code worked before the transition, my guess is that you had an open session in view filter or interceptor, and that you forgot it when migrating to annotations.

EntityManager Lifecycle when using Oracle's Virtual Private Database

I had a few questions all related to the way an entity manager is created and used in an application with respect to Virtual Private Databases, which is a feature in Oracle DB which enables Row Level Security.
In a session bean, we generally have the entity manager as a member, and its generally injected by the container. How is this entity manager managed by the container - I mean, if we want to implement a Virtual Private Database then we have to make sure that the Virtual Private Database-context remains valid for the entire user session, and we do not have to set this context everytime before we fire a query. (to include more verbiage here : a session bean implements a couple of functions and each of these functions uses the same entity manager; now, it should not be the case that we set the Virtual Private Database everytime in each of these functions which do some DB manipulations).
Further to #1, since the entity manager is cached in the session bean, do we need to explicitly close the entity manager in any scenario? (like we do for JDBC connections?)
Also, I was wondering what should be the use case(or design criteria) for using a JTA or a non-JTA datasource. Is the way we create an entity manager dependant on this?
To add w.r.t the requirement on VPD:
It would be nice if the container managed EM can somehow be made to enforce the VPD per user. Note that EM is injected in here, so there should be a mechanism to set the VPD on the connection(and later retrieve the same connection for 'this' user in 'this' session).
Without an injected EM, i think using a reference to EMF and then setting the properties for the EM can be done. Something like :
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em.getDelegate()).setProperties
It would be an overkill, if the VPD is set everytime before the query is fired, rather the connection should 'maintain' the VPD context during the user's session and later release the connection (after clearing the VPD) back to the pool.
In a session bean, an injected entity manager is container managed and by default transaction scoped.
This means when you call any method on the session bean and a transaction is started, the persistence context of the entity manager starts. When the transaction is committed or rollbacked it ends. There is thus no scenario in which you have to explicitly close the entity manager.
Furthermore, when there already is a transaction in progress, this is joined by default and when there already is a persistence context attached to said transaction it's propagated instead of a new one being created.
Stateful session beans have another option, and that's the extended persistence context. This one is coupled to the scope of the stateful bean instead of to individual transactions. You still don't have to do any closing yourself here.
Then, you can also inject an EntityManagerFactory (using #PersistenceUnit) and then get an entity manager from it: In that case you'll have an application managed entity manager. In this case you'll have to explicitly close it.
JTA datasources (transactional datasources) are by default used with container managed entity managers. The container takes care of everything here. non-JTA datasources are for situations where you need separate connections to a DB, possibly outside any running transaction, on which you can set auto commit mode, commit, rollback, etc your self.
These two different datasource types can be defined in orm.xml for a persistence unit. If you define a persistence unit with a non-JTA datasource, you typically create an entity manager for it using a factory and then manage everything your self.
Update:
Regarding the Virtual Private Database, what you seem to need here is a user specific connection per entity manager, but the normal way of doing things is coupling a persistence unit to a general data source. I guess what could be needed here is a datasource that's aware of the user's context when a connection is requested.
If you completely bypass the container and even largely bypass the JPA abstraction, you could go directly to Hibernate. It has providers that you can register globally like DriverManagerConnectionProvider and DatasourceConnectionProvider. If you provide your own implementations for these with a setter for the actual connection, you can ask these back from a specific entity manager instance just prior to using it, and then set your own connection in it.
It's doable, but needless to say a bit hacky. Hopefully someone else can give a more 'official' answer. Best would of course if Oracle provided an official plug-in for e.g. EclipseLink to support this. This document hints that it does:
TopLink / EclipseLink : Support filtering data through their
#AdditionalCriteria annotation and XML. This allows an arbitrary JPQL
fragment to be appended to all queries for the entity. The fragment
can contain parameters that can be set through persistence unit or
context properties at runtime. Oracle VPD is also supported, include
Oracle proxy authentication and isolated data.
See also How to use EclipseLink JPA with Oracle Proxy Authentication.

Resources