writing API's with JPA - spring

In a big company, our team provides API's for accessing data on a oracle DB. Until now, we used plain SQL (JDBC) to get/write the data on the database.
So most of the existing API's looked like this (ok, not always that stupid :-)
public class DummyApi {
private final DataSource datasource;
public DummyApi(javax.sql.DataSource datasource) {
this.datasource = datasource;
}
public void doSomething() throws SQLException {
Connection connection = datasource.getConnection();
PreparedStatement statement = connection.prepareStatement("plain sql query");
statement.execute();
}
}
Using such API's is simple, it doesn't matter if your end-application is plain java SE, spring or javaEE. Further, transaction-APIs works proper with this API's. We use them with spring TransactionManager (together with the TransactionAwareDataSourceProxy) and with JTA in CMA-Java EE applications.
Now we evaluate to use JPA in new API's. And the big question we currently struggle is the following: how can we provide a simple interface so that the end-application doesn't need to know about JPA? How can we initialize the EntityManager with a DataSource (for example provided as constructor parameter)? And how can we rollback if there are old, plain JDBC-APIs AND new JPA-APIs in the same transaction (begin/rollback in the end-application)?
Thanks for bringing a little light on the matter!

With JPA the datasource will normally be set in the persistence.xml. If you need some sort of dynamic datasources, then you can pass the DataSource as a property to Persistence.createEntityManagerFactory().
Most JPA providers provide a way to get the JDBC Connection if you want to mix JDBC. Normally this is accessed using em.unwrap(Connection.class). You could also use JTA or Spring to have the transaction share the same connection.

Related

Spring JPA Datasource Crash Recovery and Dynamic Changes on runtime

Hi I use spring jpa and as I understand its working mechanism truely it created at once in a singleton way.
Is it possible to change or recreate datasource on running environment.Scenario like this,Mypassword changed and if I wont stop application that time all my calls take exception.I have a mechanism to check password and change it dynamically and my others request get new password create new datasource and keep on working.
And another question is I have multiple datasource,at the application start if one of this datasource get exception that time my application cannot start.What I want if one of datasource not working ,application can continue to warmup and try to check creating datasource each related request.
I dont want to create persistencejpaconfig each request but I want to makes changes on datasource in every request if it is neccessary
#Configuration
#EnableTransactionManagement
public class PersistenceJPAConfig{
....
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("********");
dataSource.setUrl("*********");
dataSource.setUsername( "**********" );
dataSource.setPassword( "********" );
return dataSource;
}
You can simply implement your own DataSource that delegates to the real DataSource and creates a new one when the password changes.
DelegatingDataSource might be of help, either as a basis class or, since you are going to change the DataSource as a template for an implementation.

Is it possible to have two embedded databases running in Spring Boot that are populated using spring.jpa.generate-ddl?

I have two databases that I connect to in my application.
I want to set up a dev-only profile that mocks these databases using an embedded H2 database, and I would like to have their schemas auto-created by using spring.jpa.generate-ddl=true. The entity classes for each database are in different java packages, which I hope might help me here.
Is such a thing possible using spring's autoconf mechanisms?
It is possible to use multiple databases in spring boot.
But spring boot can automatically configure only one database.
You need to configure the second database yourself.
#Bean
#ConfigurationProperties(prefix="second.datasource")
public DataSource secondDataSource(){
return DataSourceBuilder
.create()
.driverClassName("org.h2.Driver")
.build();
}
If you just need a jdbc connection, this would be already sufficient. As you want to use JPA you need also a second JPA configuration, that uses the second data source.
#Bean(name="secondEntityManager")
public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder,DataSource secondDataSource){
return builder.dataSource(secondDataSource)
.packages("com.second.entity")
.build();
}
You can find the code above and more in this post

Spring jdbctemplate is it required to close the connection

I am fetching the connection in jdbctemplate in below fashion:-
getJdbcTemplate().getDataSource().getConnection()
Is it necessary to close the connection fetched in the above manner? The spring JDBCTemplate API states that connection closures will be handled automatically , so I am not sure if this is happening correctly.
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html
When you are obtaining the DataSource from the JdbcTemplate and use that to obtain a Connection you are basically completely bypassing the JdbcTemplate. You now have a very complex way of obtaining a new Connection. Because this connection isn't managed by Spring but yourself you also need to close it and apply exception handling.
It is better to use the ConnectionCallback instead to get a Connection. The JdbcTemplate will then manage the Connection and do all resource handling.
getJdbcTemplate().execute(new ConnectionCallback<Void>() {
public Void doInConnection(Connection conn) {
// Your JDBC code here.
}
});
It would even better to use one of the other JdbcTemplate methods and write proper code which would save you from messing with plain JDBC code at all.

How to disable H2's DATABASE_TO_UPPER in Spring Boot, without explicit connection URL

I'm aware that H2 has a boolean property/setting called DATABASE_TO_UPPER, which you can set at least in the connection URL, as in: ;DATABASE_TO_UPPER=false
I’d like to set this to false, but in my Spring Boot app, I don’t explicitly have a H2 connection URL anywhere. Implicitly there sure is a connection URL though, as I can see in the logs:
o.s.j.d.e.EmbeddedDatabaseFactory: Shutting down embedded database:
url='jdbc:h2:mem:2fb4805b-f927-49b3-a786-2a2cac440f44;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false'
So the question is, what's the easiest way to tell H2 to disable DATABASE_TO_UPPER in this scenario? Can I do it in code when creating the H2 datasource with EmbeddedDatabaseBuilder (see below)? Or in application properties maybe?
This is how the H2 database is explicitly initialised in code:
#Configuration
#EnableTransactionManagement
public class DataSourceConfig {
#Bean
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.ignoreFailedDrops(true)
.addScripts("db/init.sql", "db/schema.sql", "db/test_data.sql")
.build();
}
}
Also, I'm telling JPA/Hibernate not to auto-generate embedded database (without this there was an issue that two in-memory databases were launched):
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
You can't w\ the generateUniqueName, but if you call setName("testdb;DATABASE_TO_UPPER=false") you can add parameters. I doubt this is officially supported, but it worked for me.
The spring code that generates the connection url is like this:
String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false", databaseName)
You may want abandon using explicit creation via EmbeddedDatabaseBuilder. Spring Boot creates H2 instance automatically based on configuration. So I would try this in application.properties:
spring.datasource.url=jdbc:h2:file:~/testdb;DATABASE_TO_UPPER=false

Spring JDBC and Connection Object

I'm building an app using a proprietary api. To connect to the database I use a method that returns a Connection object and then on that connection I call the appropriate methods to run queries on the database for example....
Connection conn = JdbcServiceFactory.getInstance().getDefaultDatabase().getConnectionManager().getConnection();
PreparedStatement ps = conn.prepareStatement("select * from test");
If I'm choosing to use Spring MVC 3 for my next project, what must I do to get the database connection setup? From what I've seen in the documentation, I have use the datasource tag in the container and pass a URL, username, and password. As shown, I currently don't have to do that to get the connection.
At the end of the day your proprietary API must access some database (available on some server), using some credentials. You just don't see this. In Spring you must first define some DataSource. Either use existing librariess like dbcp, bonecp or c3p0 or take one provided by your application server via jndi. As long as they implement DataSource interface, it doesn't matter what approach you choose. Too much to explain each one in detail.
Once you have DataSource bean set up, I strongly recommend using JdbcTemplate which simplifies your JDBC code a lot, e.g:
List<Map<String,Object>> res = jdbcTemplate.queryForList("select * from test");
...and much more.
UPDATE: If you want to use your existing legacy API with modern frameworks expecting DataSource (pretty much all of them), implementing DataSource adapter is trivial (remaining methods can stay unimplemented, throwing UnsupportedOperationException):
public class LegacyDataSourceAdapter implements DataSource {
#Override
public Connection getConnection() throws SQLException {
return JdbcServiceFactory.getInstance().getDefaultDatabase().getConnectionManager().getConnection();
}
#Override
public Connection getConnection(String username, String password) throws SQLException {
return getConnection();
}
//other methods are irrelevant
}
Now just create an instance of LegacyDataSourceAdapter (maybe as a Spring bean) and pass it to JdbcTemplate, Hibernate, myBatis...
BTW you have here some first class example of bad API design:
Connection conn = JdbcServiceFactory.
getInstance().
getDefaultDatabase().
getConnectionManager().
getConnection();

Resources