I have some short unit tests that fail with the exception:
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statement
::
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
::
Caused by: 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-197]
The source is my Spring Data AuditProvider, specifically this line:
user = entityManager.createNamedQuery("findUserByUsernameAndTenant", User.class)
.setParameter("tenant", TenantService.DEFAULT_TENANT_ID)
.setParameter("username", UserService.USER_SYSTEM).getSingleResult();
The Error happens only when executing the whole test suite, not when running this test class only.
Here the TestRunner I'm using etc:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
@Rollback
public class MyTest {
That's my datasource URL:
spring.datasource.url: 'jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE'
So it seems "DB_CLOSE_ON_EXIT" doesn't solve the problem, any idea what's happening here?
UPDATE:
I just realized, that this happens only when running the tests in Eclipse, but they run through in the command line. While I do get the occasional:
o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'inMemoryDatabaseShutdownExecutor': 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)
but I don't get the PersistenceException and stacktrace.
Accessing the H2 Console H2 database has an embedded GUI console for browsing the contents of a database and running SQL queries. By default, the H2 console is not enabled in Spring. Then, after starting the application, we can navigate to http://localhost:8080/h2-console, which will present us with a login page.
H2 is an embedded, open-source, and in-memory database. It is a relational database management system written in Java. It is a client/server application. It stores data in memory, not persist the data on disk.
If we want to persist the data in the H2 database, we should store data in a file. To achieve the same, we need to change the datasource URL property. In the above property, the sampledata is a file name.
DB_CLOSE_DELAY
only.For in-memory database, you shouldn't use DB_CLOSE_ON_EXIT=FALSE
: you should only use DB_CLOSE_DELAY=-1
. See http://www.h2database.com/html/features.html#in_memory_databases
So you datasource should be:
spring.datasource.url: 'jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1'
It is also possible that your unit tests are executed in parallel processes. Make sure that they all run in the same VM.
If you use Maven, set forkCount
to 0
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<forkCount>0</forkCount>
</configuration>
</plugin>
I guess your various unit test classes are all annotated with @RunWith(SpringJUnit4ClassRunner.class)
?
If so, every started test class will boot Spring which will in turn boot JPA. If multiple tests classes are run in parallel, each of them creating, then dropping, the SAME in-memory database, you might have some concurrency issues.
You may also have to set surefire reuseForks
parameter to false in order to prevent JUnit from reusing the same 'context' for consecutive tests
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With