Spring’s embedded H2 datasource and DB_CLOSE_ON_EXIT - java

For unit tests (call them integration tests if you want) I have configured an embedded database in my Spring config like so:
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:schema_h2.sql" />
</jdbc:embedded-database>
Now, when running the tests from the command line, they work fine, but I get some errors at the end (harmless, but irritating):
WARN 2013-03-25 12:20:22,656 [Thread-9] o.s.j.d.e.H2EmbeddedDatabaseConfigurer 'Could not shutdown embedded database'
org.h2.jdbc.JdbcSQLException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-170]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329) ~[h2-1.3.170.jar:1.3.170]
...
at org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean.destroy(EmbeddedDatabaseFactoryBean.java:65) [spring-jdbc-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:238) [spring-beans-3.2.1.RELEASE.jar:3.2.1.RELEASE]
Now the tip contained in the exception is fine in general, but how do I add this attribute to the embedded datasource? Do I have to expand it, configure it by hand so to speak, to add such ‘advanced’ features?

Specify parameter in JDBC url jdbc:h2:~/test;DB_CLOSE_ON_EXIT=FALSE
Also for in-memory test database I suggest you to add DB_CLOSE_DELAY=-1, like this:
jdbc:h2:mem:alm;MODE=Oracle;DB_CLOSE_DELAY=-1
To add JDBC connection url to embedded-dababase change it to:
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="classpath:schema_h2.sql" />
</jdbc:initialize-database>

I had the same issue as Michael Piefel's one and tried to implement the solution that Michail Nikolaev explained.
but it did not work, somehow spring-batch, then, where are the metadata JOB_* tables are.
So, as the version of spring-jdbc used by my application is 3.0.5 and increasing the spring-framework one enters in conflict with dwr (i use it in my app) it's a geo localization based on spring, dwr and gmaps api.
I downloaded the spring-jdbc 4.0.3 release and get from it the H2EmbeddedDatabaseConfigurer.class who has DB_CLOSE_ON_EXIT=FALSE by default and replace with it the one on the spring-jdbc 3.0.5 Release and deploy-it in the war file and it works, the shutdown of the VM didn't provoke the closing of the in-memory database.
Hope this unusual solution helps if other people like me wouldn't be able to implement the other solution.

I had the same problem, but it was because I forgot to add the annotation #Entity on one of my entities. I add it and it work now !
I hope this helps someone.

Related

Shutdown Derby database using JPA not DriverManager

I have an RCP client application that uses embedded Derby in the same JVM for persistence. I access it via JPA using RESOURCE_LOCAL and Eclipse Link as a JPA provider. I leave starting the Derby instance to JPA and persistence.xml.
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, props);
Persistence.xml
<properties>
<property name="eclipse.weaving" value="false" />
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:derby:pathToDb" />
<property name="eclipselink.logging.level.sql" value="FINEST" />
<property name="eclipselink.logging.parameters" value="true" />
</properties>
At one point in the application, I need to stop the underlying Derby database. All of the examples show calling:
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
DriverManager.getConnection("jdbc:derby:pathToDb;shutdown=true");
This is problematic, especially in an RCP application with multiple class loaders (it uses OSGI under the covers). I have tried using
if (factory.isOpen())
factory.close();
but this does not shutdown the Derby instance, only the JPA connection to it.
Is there a way, using JPA, to shutdown the underlying Derby instance?
Update
I tried using the OSGI console to stop the persistence related bundles including javax.persistence, JPA and Derby. Stopping these did not release the file locks that Derby put on log files.
Update 2
Revised to clarify that the use is not in an OSGI server application.
The issue was not the classloader but an import issue.
An RCP application has a "target platform" that is dynamically searched by the framework for dependencies. This does not happen when calling Class.forName(). Once I explicitly added the Derby jar to my bundle's dependencies, the class was found and the database is shutting down properly.
Lesson learned: check the simple stuff before assuming it is hard!

Can't achieve working with p6Spy

I've tried two methods for adding p6Spy feature to my spring used project.
Route I,
http://templth.blogspot.com.tr/2004/11/integrate-p6spy-with-spring.html
I changed my driver with com.p6spy.engine.spy.P6SpyDriver and added realdriver realdriver=com.ibm.db2.jcc.DB2Driver into spy.properties file.
But somehow my realdriver is being registered before p6spy driver com.ibm.db2.jcc.DB2Driver is a real driver in spy.properties, but it has been loaded before p6spy. p6spy will not wrap these connections.Either prevent the driver from loading, or try setting 'deregisterdrivers' to true in spy.properties
Using :p6spy: prefix doesn't work for me. It says can't establish connection with that url.
So,I chose setting this deregisterdrivers=true in property file.
This time I get sql in log file but can't execute sqls. I'm able to execute sql in another sql editor. It seemed real connection went and a dummy one came.
Route II,
We use spring. So I've tried this method. Giving datasource explicitly to p6Spy. But this time spring complained of multiple java.sql.DataSource instance. Both com.firm.BasicDataFill and com.p6spy.engine.spy.P6DataSource implements DataSource. Spring can't obtain a singleton.
http://templth.blogspot.com.tr/2004/11/integrate-p6spy-with-spring.html
<bean id="dataSource" lazy-init="true"
class="com.firm.BasicDataFill">
<property name="driverClassName" value="${database.connection.driver_class}" />
<property name="username" value="${database.connection.username}" />
<property name="password" value="${database.connection.password}" />
<property name="url" value="${database.connection.url}" />
...
<property name="accessToUnderlyingConnectionAllowed" value="true" />
</bean>
<!-- bean id="myDataSource" class="com.p6spy.engine.spy.P6DataSource">
<constructor-arg>
<ref local="dataSource"/>
</constructor-arg>
</bean-->
Finally, I discovered p6spy v1.3 and 2.4.1 settings vary. Do you have any suggestion for a spring based application.
I would recommend starting with the latest version of P6Spy 2.x. You should also REPLACE your spy.properties file with the default version for 2.X which is documented here. Depending on your application server, you might need to set the 'realdriver' setting in spy.properties to include 'com.ibm.db2.jcc.DB2Driver'. However, this is only needed when you are using an application server that prevents the automatic registration of JDBC Drivers.
To use P6Spy with Spring, the easiest method is to wrap your current data source bean with P6SpyDataSource as discussed here. The example in that answer shows a JNDI data source being wrapped but it can be used to wrap any data source. Note: If you are wrapping the data source is P6SpyDataSource, you do NOT need to modify the JDBC URL.
If you continue to have problems, please add a bit more information to your question. The following information would be helpful in troubleshooting:
The version of P6Spy being used
The contents of spy.properties
The definition of your datasource (including app server config if
using JNDI)
The type of app server and version being used
Stacktrace containing whatever error you might have received.
Have a look at Log4jdbc it'll do the job https://code.google.com/p/log4jdbc/

Multi-tenancy in Hibernate - multi databases (SQLite)

I'm trying to do multi-tenancy with multi databases. From this chapter I took MultiTenantConnectionProviderImpl.
And here I have problem. Eclipse cannot find class ConnectionProviderUtils. I'm using Maven with dependency:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.4.Final</version>
</dependency>
I hate to disapoint you but I was running in the same problem a while back. The point is the ConnectionProviderUtil is quite misleading in the documentation. There is no such thing. The ConnectionProviderUtil is something you have to implement yourself. I implemented this by constructing my own DataSource (a c3p0 pooled one) in the MultiTenantConnectionProvider and handing out connection from there.
So you have to implement it from scratch yourself. For reference here is my way to a Solution. Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1
For the multi DB approach you can just autowire the different DataSources into the MultiTenantConnectionProvider and switch based on the TenantIdentifier. See this answer for more details: https://stackoverflow.com/a/16769595/2319179
Edit:
If you use Spring you can set up a DataSource in the appcontext like this:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="<jdbcdriver>" />
<property name="url" value="jdbc:SQLServer://<host>:<port>;databaseName=<dbname>" />
<property name="username" value="<user>" />
<property name="password" value="<pw>" />
</bean>
If you need to build it from java you can do it like this:
cpds = new DriverManagerDataSource();
cpds.setDriverClass(<jdbc.driver>);
cpds.setJdbcUrl(<jdbc.url>);
cpds.setUser("<user>");
cpds.setPassword("<pw>"));
A quick googlesearch should bring up the right driver.
ConnectionProvider is what you use to customize your strategy for obtaining connections. Provided all schemas are the same, this is one of the best places to implement multi-tenancy.
Along with the ConnectionProvider, you'll need a ThreadLocal to hold the "tenancy" and probably a ServletFilter to set it up (from session variable, set at login). This is similar to how Spring's OpenSessionInViewFilter works.
All in all, this can provide a very simple & effective solution:
http://literatejava.com/hibernate/multi-tenancy-architecture-with-hibernate/

Oracle connections in Spring

I am using Oracle 9 JDBC Thin Driver - the connection string I have used for standard JDBC was:
jdbcConn.connect("jdbc:oracle:thin:myDevDb/myDevDb#fooServer:1521:MYSIDNAME");
...just trying to get my head around using this kind of connection in Spring 2.5.
How do you wire up Spring to an Oracle connection - think it has something to do with an XML conifg file but not sure, there seems to be a couple of ways to do it.
Any help much appreciated...
LATEST EDIT
Thanks to those who have responded so far - but I need a bit of a "leg up" - on the part where you configure in the database connection string setup in your config, where do you put this info, and how?
I have an existing Java web application - and I am trying to get to grips with how I 'shoehorn' Spring into my existing app.
There are a few ways of doing this and it depends on what your environment is. If you're using Spring there's a fair chance you're deploying a Web application or you're otherwise in a J2EE environment. If this is the case (and arguably even if it isn't) you probably want to configure a DataSource.
This is a fairly minimal solution:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
The above is using the Apache (Jakarta Commons) database connection pooling but your appserver probably has an alternative you may want to use instead. Also, different database vendors have their own data source implementations too (eg OracleDataSource and OracleXADataSource for Oracle).
Note the use of properties like jdbc.username. This is a typical configuration because database configurations typically vary between environment. You can activate a property configurator with something like:
<bean id="jdbcConfiguration" class="org.springframework.beans.factory.config.PropertiesPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
Now you probably want transactions too I would imagine. The easiest way is to use a platform transaction manager but, like with most things Spring, there are multiple ways of doing it.
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
After this you can use this bean directly or (arguably more common) you can use declarative transactions with AOP (annotations).
More on these subjects in the (superb) Spring reference documentation.

Spring JTA TransactionManager config: Supporting both Tomcat and JBoss

I have a web application using JPA and JTA with Spring. I would like to support both JBoss and Tomcat. When running on JBoss, I'd like to use JBoss' own TransactionManager, and when running on Tomcat, I'd like to use JOTM.
I have both scenarios working, but I now find that I seem to need two separate Spring configurations for the two cases. With JOTM, I need to use Spring's JotmFactoryBean:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<bean class="org.springframework.transaction.jta.JotmFactoryBean"/>
</property>
</bean>
In JBoss, though, I just need to fetch "TransactionManager" from JNDI:
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef" value="true" />
<property name="jndiName" value="TransactionManager" />
<property name="expectedType"
value="javax.transaction.TransactionManager" />
</bean>
</property>
</bean>
Is there a way to configure this so that the appropriate TransactionManager - JBoss or JOTM - is used, without the need for two different configuration files?
I think you have missed the point of JNDI. JNDI was pretty much written to solve the problem you have!
I think you can take it up a level, so instead of using the "userTransaction" or "transactionManager from JNDI" depending on your situation. Why not add the "JtaTransactionManager" to JNDI. That way you push the configuration to the JNDI where it is supposed to be instead of creating even more configuration files [ like there aren't enough already ;) ].
You can use PropertyConfigurerPlaceholder to inject bean references as well as simple values.
For example if you call your beans 'jotm' and 'jboss' then you could inject your TM like:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE">
<property name="location" value="classpath:/path/to/application.properties"/>
</bean>
<bean id="jotm">...</bean>
<bean id="jboss">...</bean>
<bean id="bean-requiring-transaction-manager">
<property name="transactionManager" ref="${transaction.strategy}"/>
</bean>
Then you can swap transaction managers using
transaction.strategy=jotm in a properties file
-Dtransaction.strategy=jotm as a system property
This is one possible approach. See my blog for a more complete example.
Hope this helps.
If you are using Spring 2.5 you can use <tx:jta-transaction-manager/>. I have not used it with JBoss but it should work for you according to section 9.8 Application server-specific integration from the Spring reference manual.
The <tx:jta-transaction-manager/> approach will look for a transaction manager in several default locations listed here. If your JBoss transaction manager is not in one of those locations, I suggest you move it, if possible, or move it in Tomcat so that both containers have their TM in the same JNDI location.
Just adding my experience here so I don't have to re-suffer the experience again.
As bmatthews68, Chochos and these posters have said, use <tx:jta-transaction-manager/> in your Spring bean file; it definitely provides the appropriate level of abstraction and there's no need to do anything extra on the Spring side.
As for Tomcat, I declared <Transaction factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60" /> in the default/shared conf/context.xml file, which binds to java:comp/UserTransaction. As this is one of the places searched for by Spring, you shouldn't need to do anything else.
One gotcha though: if like me you use Maven, make sure you exclude any dependencies on the javax.transaction:jta jar or set the scope to provided. Otherwise you will experience classloader issues.

Categories