Embedded database and multiple catalogs - java

I want to create integration tests for my repositories. The production database is Sybase and it consists of multiple catalogs in which there are multiple schemas.
In my code I use multiple queries I am selecting data across different catalogs: ex:
select *
from catalog_a.schema_a.table_1 aa1, catalog_b.schema_a.table_2 ba2
where aa1.c1 = ba2.c2
So for the tests I would like to create embedded database, like H2, HSQLDB or something different. I was trying to find something that would allow me to simulate prod db with multiple catalogs, but I couldn't make it work. Please advice and suggest the solution.
I am writing app in java/spring. Additional trick here is that my app is creating only one DataSource to database.

HSQLDB supports only a single catalog and the name is checked when the catalog is specified in a query. You can change the catalog name from the default PUBLIC to something else. For example:
ALTER CATALOG public RENAME TO to catalog_a
But using two different catalog names is not supported.
If your schema or table names in the two catalogs are different, you could modify the source code of HSQLDB and disable the catalog name check for your tests in the method org.hsqldb.ParserDQL.checkValidCatalogName(String name)

I managed to achieve this in H2 via IGNORE_CATALOGS property and version 1.4.200.
However, the url example from their docs did not seem to work for me, so I added a statement in my schema.xml:
SET IGNORE_CATALOGS = true;

Related

How to select schema at runtime using Hibernate?

I already have an existing code base, where schema(like db_1, db_2..) are created at run time.
We are currently using JdbcTemplate, using that its quite easy to append schema in the native SQL queries some thing like :-
sql = " Select * from "+schema+".user";
jdbcTemplate.query(sql, new UserMapper());
Now I want to know is how to provide schema to hibernate at runtime like I did with the jdbcTemplate?
What connection url should I provide in hibernate.cfg.xml so that it doesn't connects to a single schema rather whole database?
Any suggestions will be helpfull.
P.S: I am new to hibernate (So I might have missed something stupid)
I know of two options:
Use native SQL query binding results to JPA entities. Details here.
Use Hibernate multi-tenancy. Details here and here.
Although I haven't tried either.

Apache ibatis postgresql selectList how it it works

I have installed postgresql enterprise DB and created some tables
In one of the example. I see the following code.
import org.apache.ibatis.session.SqlSession;
.....
SqlSession session = sessionFactory.openSession();
.....
List list = session.selectList("findAllData-Data", params);
What it does? findAllData-Data means what? I have only created tables in postgresql, but I don't see the table name in above code
Check up the documentation for selectList
"findAllData-Data" is the unique identifier matching the statement to use. Statements are usually defined in some mapper .xml file or in newer versions in annotation of a class, so grep your code for findAllData-Data in order to find the definition.

SQL\HQL queries repository

While working on some java projects i've saw some sort of SQL repository.
The idea was to place all queries in one(or few) xml files and retrieve them when needed by name. Something like this:
String sql = getSQLRepository().getSQL("SELECT_ALL_ROWS", params)
String sql2 = getSQLRepository().getSQL("SELECT_ROWS_WITH_COND", params)
In my current Grails project i have a lot of HQL queries in dozens of classes and it's hard to track them all. It seems that HQL repository would be very nice solution.
So could anyone tell if some sort of SQL\HQL repository implementation allready present or there are better solutions present ?
Have a look at Mapping Queries in Hibernate reference.
After we started use the http://source.mysema.com/display/querydsl there is no need to think about text queries and how to manage them.
I'd recommend you to use the good old properties files. You can put them into your classpath and then use as following:
Properties sql = new Properties();
properties.load(getClass().getResourceAsStream("sql.properties"));
////////
String query = sql.get("SELECT_ALL_ROWS");
I'm sorry, and it doesn't relate to Hibernate, but when I worked with iBatis, - there are the situation as you are writing about exactly. A few xml (partially generated itself) files, containing SQL queries, which was easily to use in DAO

Running hibernate tool annotation generation without the "catalog" attribute

when i run my hibernate tools
it reads from the db and create java classes for each tables,
and a java class for composite primary keys.
that's great.
the problem is this line
#Table(name="tst_feature"
,catalog="tstdb"
)
while the table name is required, the "catalog" attribute is not required.
sometimes i want to use "tstdb", sometimes i want to use "tstdev"
i thought which db was chosen depends on the jdbc connection url
but when i change the jdbc url to point to "tstdev", it is still using "tstdb"
so,
i know what must be done,
just don't know how its is done
my options are
suppress the generation of the "catalog" attribute
currently i'm doing this manually (not very productive)
or i could write a program that parses the java file and remove the attribute manually
but i'm hoping i don't have to
OR
find a way to tell hibernate to ignore the "catalog" attribute and use the schema that is explicitly specified.
i don't know the exact setting i have to change to achive this, or even if the option is available.
You need to follow 3 steps -
1) In the hibernate.cfg.xml, add this property
hibernate.default_catalog = MyDatabaseName
(as specified in above post)
2) In the hibernate.reveng.xml, add all the table filters like this
table-filter match-name="MyTableName"
(just this, no catalog name here)
3) Regenerate hibernate code
You will not see any catalog name in any of the *.hbm.xml files.
I have used Eclipse Galileo and Hibernate-3.2.4.GA.
There is a customization to the generation, that will tell what tables to put in what catalog.
You can specify the catalogue manually (in reveng file, <table> element), or programmatically (in your custom ReverseEngineeringStrategy class if I remember well).
Also, I recently had to modify the generation templates.
See the reference documentation :
http://docs.jboss.org/tools/archive/3.0.1.GA/en/hibernatetools/html_single/index.html#hibernaterevengxmlfile
you can customize the catalogue of each of your tables manually
https://www.hibernate.org/hib_docs/tools/viewlets/custom_reverse_engineering.htm watch a movie that explains a lot ...
http://docs.jboss.org/tools/archive/3.0.1.GA/en/hibernatetools/html_single/index.html#d0e5363 for customizing the templates (I start with the directory that's closest to my needs, copy all of them in my own directory, then edit as will)
Sorry, this could get more precise, but I don't have access to my work computer right now.
The attribute catalog is a "connection" attribute and should be specified in the "connection" config file hibernate.cfg.xml and NOT in a "data" config file *.hbm.xml.
I generate hibernate code via ant task <hibernatetool> and I put this replace task after regeneration (replace schema-name with your database).
<replace dir='../src' token='catalog="schema-name"' value=''>
So, after generation, attribute catalog has been removed.
This is a workaround, but code generated works in my development a production environment with different schema-name.

What are the possible values of the Hibernate hbm2ddl.auto configuration and what do they do

I really want to know more about the update, export and the values that could be given to hibernate.hbm2ddl.auto
I need to know when to use the update and when not? And what is the alternative?
These are changes that could happen over DB:
new tables
new columns in old tables
columns deleted
data type of a column changed
a type of a column changed its attributes
tables dropped
values of a column changed
In each case what is the best solution?
From the community documentation:
hibernate.hbm2ddl.auto Automatically validates or exports schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.
e.g. validate | update | create | create-drop
So the list of possible options are,
validate: validate the schema, makes no changes to the database.
create-only: database creation will be generated.
drop: database dropping will be generated.
update: update the schema.
create: creates the schema, destroying previous data.
create-drop: drop the schema when the SessionFactory is closed explicitly, typically when the application is stopped.
none: does nothing with the schema, makes no changes to the database
These options seem intended to be developers tools and not to facilitate any production level databases, you may want to have a look at the following question; Hibernate: hbm2ddl.auto=update in production?
There's also the value of none to disable it entirely.
The configuration property is called hibernate.hbm2ddl.auto
In our development environment we set hibernate.hbm2ddl.auto=create-drop to drop and create a clean database each time we deploy, so that our database is in a known state.
In theory, you can set hibernate.hbm2ddl.auto=update to update your database with changes to your model, but I would not trust that on a production database. An earlier version of the documentation said that this was experimental, at least; I do not know the current status.
Therefore, for our production database, do not set hibernate.hbm2ddl.auto - the default is to make no database changes. Instead, we manually create an SQL DDL update script that applies changes from one version to the next.
First, the possible values for the hbm2ddl configuration property are the following ones:
none - No action is performed. The schema will not be generated.
create-only - The database schema will be generated.
drop - The database schema will be dropped.
create - The database schema will be dropped and created afterward.
create-drop - The database schema will be dropped and created afterward. Upon closing the SessionFactory, the database schema will be dropped.
validate - The database schema will be validated using the entity mappings.
update - The database schema will be updated by comparing the existing database schema with the entity mappings.
The hibernate.hbm2ddl.auto="update" is convenient but less flexible if you plan on adding functions or executing some custom scripts.
So, The most flexible approach is to use Flyway.
However, even if you use Flyway, you can still generate the initial migration script using hbm2ddl.
I would use liquibase for updating your db. hibernate's schema update feature is really only o.k. for a developer while they are developing new features. In a production situation, the db upgrade needs to be handled more carefully.
Although it is quite an old post but as i did some research on the topic so thought of sharing it.
hibernate.hbm2ddl.auto
As per the documentation it can have four valid values:
create | update | validate | create-drop
Following is the explanation of the behaviour shown by these value:
create :- create the schema, the data previously present (if there) in the schema is lost
update:- update the schema with the given values.
validate:- validate the schema. It makes no change in the DB.
create-drop:- create the schema with destroying the data previously present(if there). It also drop the database schema when the SessionFactory is closed.
Following are the important points worth noting:
In case of update, if schema is not present in the DB then the schema is created.
In case of validate, if schema does not exists in DB, it is not created. Instead, it will throw an error:- Table not found:<table name>
In case of create-drop, schema is not dropped on closing the session. It drops only on closing the SessionFactory.
In case if i give any value to this property(say abc, instead of above four values discussed above) or it is just left blank. It shows following behaviour:
-If schema is not present in the DB:- It creates the schema
-If schema is present in the DB:- update the schema.
hibernate.hbm2ddl.auto automatically validates and exports DDL to the schema when the sessionFactory is created.
By default, it does not perform any creation or modification automatically on DB. If the user sets one of the below values then it is doing DDL schema changes automatically.
create - doing creating a schema
<entry key="hibernate.hbm2ddl.auto" value="create">
update - updating existing schema
<entry key="hibernate.hbm2ddl.auto" value="update">
validate - validate existing schema
<entry key="hibernate.hbm2ddl.auto" value="validate">
create-drop - create and drop the schema automatically when a session is starts and ends
<entry key="hibernate.hbm2ddl.auto" value="create-drop">
If you don't want to use Strings in your app and are looking for predefined constants have a look at org.hibernate.cfg.AvailableSettings class included in the Hibernate JAR, where you'll find a constant for all possible settings. In your case for example:
/**
* Auto export/update schema using hbm2ddl tool. Valid values are <tt>update</tt>,
* <tt>create</tt>, <tt>create-drop</tt> and <tt>validate</tt>.
*/
String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
validate: validates the schema, no change happens to the database.
update: updates the schema with current execute query.
create: creates new schema every time, and destroys previous data.
create-drop: drops the schema when the application is stopped or SessionFactory is closed explicitly.
I Think you should have to concentrate on the
SchemaExport Class
this Class Makes Your Configuration Dynamic
So it allows you to choose whatever suites you best...
Checkout [SchemaExport]
validate: It validates the schema and makes no changes to the DB.
Assume you have added a new column in the mapping file and perform the insert operation, it will throw an Exception "missing the XYZ column" because the existing schema is different than the object you are going to insert. If you alter the table by adding that new column manually then perform the Insert operation then it will definitely insert all columns along with the new column to the Table.
Means it doesn't make any changes/alters the existing schema/table.
update: it alters the existing table in the database when you perform operation.
You can add or remove columns with this option of hbm2ddl.
But if you are going to add a new column that is 'NOT NULL' then it will ignore adding that particular column to the DB. Because the Table must be empty if you want to add a 'NOT NULL' column to the existing table.
Since 5.0, you can now find those values in a dedicated Enum: org.hibernate.boot.SchemaAutoTooling (enhanced with value NONE since 5.2).
Or even better, since 5.1, you can also use the org.hibernate.tool.schema.Action Enum which combines JPA 2 and "legacy" Hibernate DDL actions.
But, you cannot yet configure a DataSource programmatically with this. It would be nicer to use this combined with org.hibernate.cfg.AvailableSettings#HBM2DDL_AUTO but the current code expect a String value (excerpt taken from SessionFactoryBuilderImpl):
this.schemaAutoTooling = SchemaAutoTooling.interpret( (String) configurationSettings.get( AvailableSettings.HBM2DDL_AUTO ) );
… and internal enum values of both org.hibernate.boot.SchemaAutoToolingand org.hibernate.tool.schema.Action aren't exposed publicly.
Hereunder, a sample programmatic DataSource configuration (used in ones of my Spring Boot applications) which use a gambit thanks to .name().toLowerCase() but it only works with values without dash (not create-drop for instance):
#Bean(name = ENTITY_MANAGER_NAME)
public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier(DATA_SOURCE_NAME) DataSource internalDataSource) {
Map<String, Object> properties = new HashMap<>();
properties.put(AvailableSettings.HBM2DDL_AUTO, SchemaAutoTooling.CREATE.name().toLowerCase());
properties.put(AvailableSettings.DIALECT, H2Dialect.class.getName());
return builder
.dataSource(internalDataSource)
.packages(JpaModelsScanEntry.class, Jsr310JpaConverters.class)
.persistenceUnit(PERSISTENCE_UNIT_NAME)
.properties(properties)
.build();
}
To whomever searching for default value...
It is written in the source code at version 2.0.5 of spring-boot and 1.1.0 at JpaProperties:
/**
* DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto"
* property. Defaults to "create-drop" when using an embedded database and no
* schema manager was detected. Otherwise, defaults to "none".
*/
private String ddlAuto;
With all above said...
Notice this property is called dll.auto and should only control dll operations(create/drop schema/table), I found surprisingly that it has to do with dml, too: only update will allow insert data, which is dml operation.
Got caught by this when trying to populate data into a in-memory database; only update works.

Categories

Resources