I have a method that I've annotated with the #Transactional annotation.
The problem is, the datasource that the code runs against can change! Briefly, is it possible to change the transaction's datasource while the application is running?
In depth:
The application lets users select a database to run sql against. They can change the database at runtime. I'd like the application to run all the sql in a transaction - the sql groups are always against the same datasource, so that's not an issue.
The issue is, I don't know how to changem the transaction to use a different datasource. Varying articles have suggested the JTATransactionManager, but we're on tomcat, so no dice.
Is there a simple way to do this, or will we need to ditch the #Transactional annotation and do something else?
And if so, what is that "something else?"
Oh, the database is db2, if that's any use!
thanks!
One of the possible solution
Configure all the possible datasources in spring config
a. Datasource1 for DB1
b. Datasource2 for DB2 etc..
Maintain a map of above datasource in a service class and create spring's JDBCTemplate out of selected datasource based on some key from map.
Related
Is there any possible solution to dynamically create a datasource at runtime? I have come across AbstractRoutingDataSource e.g. here a few times however in my case I would not know the database name at the time of config beans starting up as we will be creating databases during client on-boarding and would prefer not to have to bounce the app, so I would want to select the correct datasource based on some client id in the request header, and add the new datasource to the spring context on the first request for this client.
Yes, like any other bean you can add DataSource bean in runtime.
There are several ways to do this: https://medium.com/#venkivenki4b6/spring-dynamically-register-beans-in-4-ways-at-run-time-c1dc45dcbeb9
I'm currently working on implementing schema-based multi-tenancy for my Spring Boot / JdbcTemplate API application. I figured out that for it to work, in the DAO layer, I need to dynamically change the schema of the DataSource used by JDBCTemplate during the runtime, in other word create a new one, but I can't find any information on how to set properly the schema for the DataSource I'm creating.
EDIT
Here are some details that might be important : the schema is defined in the url of the API endpoints I created, as a mandatory variable: if the user calls the URL localhost:9090/schema/MyNewSchema/Test, the schema variable is MyNewSchema and I have to create a DataSource with the proper pointed schema MyNewSchema.
Found a possible answer if someone faces the same issue : https://springboot-vuejs-reactjs.blogspot.com/2019/08/springboot-multi-tenancy-with.html
I decided to use an AbstractDataSource class, as mentioned in the article, and to override the public DataSource dataSource() bean in the #SpringBootApplication class, with an injection of the AbstractDataSource class created earlier. This allows me to manipulate the DataSource used by JDBCTemplate dynamically during the application runtime.
Furthermore, in my AbstractDataSource class, the DataSource objects I manipulate are HikariDataSource, allowing me to define the schema I want the DataSource to point with a hikariDs.setConnectionInitSql("ALTER SESSION SET CURRENT_SCHEMA = MY_SCHEMA") statement (cf Configure OracleDataSource programmatically in Spring Boot with a default schema). In my case, I'm using Postgresql, so the SQL statement is SET SEARCH_PATH TO <schema-name>
It works pretty well !
I went through the Data Access With Spring tutorial and the in memory database they use in step 3 is working. But, I'm not clear on what I need to add/change to get it to query my development (Oracle) database now?
I want to use Hibernate, do I still need this JPAConfiguration class or would I have something Hibernate specific?
Please don't just post a link to the Hibernate reference. I'm reviewing that as well, but since I'm also using Spring, it's not clear to me the proper way to load the hibernate.cfg.xml and inject the Hibernate session in that context.
Don't be blocked by the fact that the class is called JPAConfiguration. You need to understand what the class does. Note that it has the annotation #Configuration which you can use along with AnnotationConfigApplicationContext to produce a Spring bean context.
That functionality is described in the Spring documentation for The IoC container.
What you need to change is how your DataSource and EntityManagerFactory beans are created. You'll need to use a DataSource that gets Connection instances from a JDBC Driver that supports Oracle databases.
I've got a project of mine in which I would like to take advantage of Hibernate to increase the speed of development for basic operations, combined with Spring's JDBC template to be able to use my own SQL queries for some specific operations and not loose control, since there are some heavy, performance demanding operations.
Is this even possible or a good idea?
Yes, it is possible. And yes, it's a good idea.
The documentation says:
For distributed transactions across multiple Hibernate session factories, simply combine JtaTransactionManager as a transaction strategy with multiple LocalSessionFactoryBean definitions. Each DAO then gets one specific SessionFactory reference passed into its corresponding bean property. If all underlying JDBC data sources are transactional container ones, a business service can demarcate transactions across any number of DAOs and any number of session factories without special regard, as long as it is using JtaTransactionManager as the strategy.
[...]
HibernateTransactionManager can export the Hibernate JDBC Connection to plain JDBC access code, for a specific DataSource. This capability allows for high-level transaction demarcation with mixed Hibernate and JDBC data access completely without JTA, if you are accessing only one database. HibernateTransactionManager automatically exposes the Hibernate transaction as a JDBC transaction if you have set up the passed-in SessionFactory with a DataSource through the dataSource property of the LocalSessionFactoryBean class. Alternatively, you can specify explicitly the DataSource for which the transactions are supposed to be exposed through the dataSource property of the HibernateTransactionManager class.
So, if you're in a full-stack Java EE container supporting JTA transactions and DataSources, use a DataSource defined in your Java EE container and a JTATransactionManager.
If you'e in a simple web container such as Tomcat, use a Spring-provided DataSource and a HibernatTransactionManager.
I'm a Spring novice user.
I have a database table which is static in nature and contains only a few records.I want a Map-like structure(id - name) that holds two columns of this table. This Map must be loaded/initialized when the web application is started and must be applicable throughout the application's context, independent of the users sessions and must be read-only. This way, I can save a lot of DB queries as the different operations will simply read from this Map.
While I'm aware of ServletContextListener etc. of Java EE, I don't know how to achieve the same in Spring. Is a Spring Service bean the right place/way to initialize and store such a Map?
Please guide me about the same.
You can create a regular spring bean exposing a method which loads the data you require from the database and stores it in your map. Annotate this method with #PostConstruct and spring will ensure that it is called when your application context starts, hence loading your map.
You could use springs JdbcTemplate to load your data within this method
See Spring PostConstruct doco for information on the #PostConstruct annotation
See JdbcTemplate doco for information on JdbcTemplate
You can configure lists, sets and maps in a Spring XML configuration. See here for more examples.