How can I get H2 to work with Spring? - java

I am writing a test which extends Spring's AbstractTransactionalJUnit4SpringContextTests.
In my application code I have a method which I call inside the test annotated by the following:
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
Problem
I run into a problem while using H2 as the underlying data source in-memory mode. It gives me the error:
Caused by:org.h2.jdbc.JdbcSQLException: Timeout trying to lock tableMY_TABLE[50200-131]
When I remove the propagation, it works, and when I use an alternative database such as Oracle or MySQL with Propagation.REQUIRES_NEW, everything works fine.
I am using Spring 3.0.2-RELEASE and H2 1.2.131.
How can I get H2 to work with Spring?

I don't know what the problem is, but try appending ;MVCC=TRUE to the database URL.

Had the same problem doing JUnit Tests with play-framework Jobs (that run into separate threads) and trick provided by Thomas works! (appending ;MVCC=TRUE to the database URL.)
I guess this MVCC option enables 'Row Level Locking' instead of locking the whole TABLE, and so the LOCK issue is gone, see "Row Level Locking" feature on:
http://www.h2database.com/html/features.html#in_memory_databases
'Row Level Locking' supported in H2: <*9 When using MVCC (multi version concurrency).>

Related

Is it possible to rollback the database after each JUnit test case without using Spring framework?

I'm trying to test the service which updates multiple tables from the database and I want to rollback the database to previous state after each test case. All solutions I have found are using #Transactional and #Rollback from Spring framework, but since my application is not a Spring web application, I would like to use javax #Transactional, which does not work for me.
Is this possible with javax at all or anything else except the Spring?
Rollback a transaction isn't a good idea for test (integration test) as the constraint may not be validated before the commit.
You should:
have a DB only for integration tests (or an embedded db or a container db or in RAM db)
execute, for example in a class rule or in a test rule, script SQL in order to bring the db in a known status
execute a test
if test modifies the db then run a truncate of tables modified (again or in your class or test rule) and, before peform a new test, run again the script at point 2
run integration tests not so often as unit tests
Better idea is to use in-memory database:
H2 https://www.h2database.com/
Recommendation for a Java in memory database
Not always and not everything in database can be rolled-back to initial state ( ex. sequences ).

How to use the actual database for integration testing?

There were some proposed solutions to the question "How to test SQL statements in an application" -
Using RAM memory - I can't change the configuration of staging environment where testing happens.
Using H2 - Not very compatible even in PostgreSQL mode
Use the same database to run the tests.
Using in-memory mode - PostgreSQL doesn't have one.
The third one was viable and I looked into Test Containers which is actually a beautiful solution but a relatively new one. As a result, our company is sceptical of adopting it.
We use Mybatis to access PostgreSQL.
Another way would be to recreate entire schema and populate required tables before tests. Here is the problem, I could create and delete schema with tables with the same name. To avoid name collision I'd have to change schema's name, as a result, even queries should be renamed which is not at all preferred. Is there a way to do this without changing queries but pointing them to the dummy schema.
You should NOT change your queries. In tests you should only change the connection url your application will use. The problem is, how to get that url working.
To have full test coverage you need the same db (as you noticed, h2 and other in-memory db are not very compatible). postgres doesn't have in-memory mode so you have to manage the lifecycle yourself. there is a few decisions you have to make. some of them:
where will you get the db from: require all the devs to provide postgres (installation / docker / vagrant) or automate the setup?
how to prepare db for tests: manual schema setup and cleanup?
how to reset db between tests: restart? always rollback? predefined and separately defined content? some kind of reverse operations?
if and how to make those tests fast?
there are some tools that can help you solve some of the problems:
testcontainers will help you provide
db.
dbunit - will help you prepare data for your test.
cons:
a lot of work is required to create and maintain schema and data. especially when your project is in a intensive development stage.
it's another abstraction layer so if suddenly you want to use some db feature that is unsupported by this tool, it may be difficult to test it
testegration - intents to provide you full, ready to use and extensible lifecycle (disclosure: i'm a creator).
cons:
free only for small projects
very young project
you can also fill the gaps on your own. as always it's a trade: time vs money
you can define database configuration for test purpose and connect to your real database base for execute tests. you should access to test database configuration in test classes.
for example, if you use spring and hibernate to connect to the database, you can define a test hibernate configuration xml file where it connect to test database. then in your test classes, use this configuration file as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguratiion({testHibernate.xml, testSpring.xml , .... })
#TestExecutionListeners({...})
public class TestClass {
....
#Test
public void test1(){
...
}
}
so, you can access your test hibernate session factory to execute your queries.

Hibernate-Search with Lucene without database? [duplicate]

Is it possible to use hibernate-search only for it's annotations (bean => document/document => bean mapping), without using a database at all? If so, are there any online samples that show basically how to set this up?
I found the following: http://mojodna.net/2006/10/02/searchable-annotation-driven-indexing-and-searching-with-lucene.html, but I'd prefer hibernate-search if it supports my use case.
Hibernate search 3.4 has decoupled the query engine from Hibernate Core. For instance, Hibernate Search is reused to implement queries with Infinispan. I don't know if the code is packaged so that you could use HS with, let's say Spring and JDBCTemplate (something I would like to do). That's a lead I will investigate later but maybe you can check it out...
Starman is correct, Hibernate Search in version 3.4 is abstracting the search engine from Hibernate Core, and the Infinispan Query is an integration example which works fine without a database. There would be no problems with Spring either, but you'd need to make sure to send update event to the query engine so that the index doesn't get out of synch. When using Hibernate the advantage is that it transparently listens for changes to the database and applies them to the index at transaction commit, so the index is always in synch (or close, if configuring Search to use async backends).
I'd suggest to look into the code of Infinispan Query, as it's very small and just delegating calls to expose an Infinispan flavoured API. Most of the code is tests or integration to properly manage the lifecycle of the engine: start and stop it together with Infinispan.
I don't think that's possible because when you enable Hibernate search you are enabling that on a Entity and that Entity has references to the table and the search index.

How to generically test a database connection with hibernate

I have a service method on an api that can be called to check the health of my database connection.
The method is pulling the query string from a properties file (depends on DB vendor, using Sybase and HSQL for now, more in future), and executing it. Then the method lets the caller know if it succeeded or failed.
In addition to this, I was using the Query.setHint("javax.persistence.query.timeout") to set a timeout on the query:
javax.persistence.EntityManager entityManager;
...
Query heartbeatQuery = entityManager.createNativeQuery(heartbeatQueryString);
heartbeatQuery.setHint("javax.persistence.query.timeout", heartbeatTimeout);
heartbeatQuery.getResultList();
My problem is the timeout property is working against my Sybase DB, but not against my HSQL DB. It sounds like it depends on the vendor, so I don't know for sure when it will work.
Is there a better way to generically test the DB connection & include some kind of timeout parameter?
Well sadly no. JPA's query hints are not mandatory, i.e. it's up to the implementator (EclipseLink, Hibernate, etc) to enforce them or not. Moreover, even if the implementator does chose to recognize a certain query hint, if that hint's functionality is not supported by the database then it won't work (here some implementators are nice and tell you if a certain hint won't work agains the current db while others fail silently). In the case of HSQLDB there's no way to set the query timeout. You can only set a timeout for the login (i.e. how long should it wait for a successful login before failing), but not for the queries duration.
Things are not so grim however. On the one hand, even if you'd solve this, you'd still stumble over other issues with HSQLDB, as it does not support a lot of other nice functionalities that most dbs have. You should only use HSQLDB for basic integration/unit testing. For more involved testing, you can use the integrated MySQL Java library. You can find it here:
http://dev.mysql.com/doc/refman/5.0/en/connector-mxj.html
This is simply a packaged fully working Mysql server, which has a Java api for star and stop, works on most major OSs (win,lin, os x, etc). This way you can have your integration tests start a real Mysql server, and try your code there, where such stuff as a query timeout hint will work fine.

Viewing Data From Transactional Tests - Hibernate + Spring + MySQL

I have a bunch of tests in a Hibernate/Spring application. Yesterday, I transitioned them from using the JUnit 3.8 base test class provided by Spring to the JUnit 4.4 one.
Everything works great, because now, my tests are wrapped in transactions, and data created/modified is automatically rolled back (instead of me writing code to delete newly-created entities).
The only problem is that I cannot peek into the database during test execution. If a test fails, I often add breakpoints near the end and peer into the MySQL database via SQL Yog to see what's going on. But now, I just see empty tables. (I mean in integration tests that simulate production very closely and actually touch the database.)
I tried setting the global isolation level to read uncommitted, but it didn't change the fact that I can't see the data. How can I configure Spring/Hibernate to allow me to view the data from another process?
I had the same issue, and found that setting the session isolation level while using YOG sometimes helped.
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
This only uncovered another disturbing issue - while running tests, the Hibernate didn't actually run some of the actions unless I used HibernateTemplate.flush(); after every Hibernate operation.
As this very annoying, I finally set Hibernate so it would always flush queries, like this:
HibernateTemplate hibernateTemplate;
...
hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_ALWAYS);

Categories