Hibernate on Oracle AND SQLServer - java

I'm introducing a DAO layer in our application currently working on SQL Server because I need to port it to Oracle.
I'd like to use Hibernate and write a factory (or use dependency injection) to pick the correct DAOs according to the deployment configuration. What are the best practices in this case? Should I have two packages with different hibernate.cfg.xml and *.hbm.xml files and pick them accordingly in my factory? Is there any chance that my DAOs will work correctly with both DBMS without (too much) hassle?

Assuming that the table names and columns are the same between the two, you should be able to use the same hbm.xml files. However you will certainly need to supply different a Hibernate Configuration value (hibernate.cfg.xml), as you will need to change Hibernate's dialect from SQLServer to Oracle.
If there are slight name differences between the two, then I would create two sets of mapping files - one per Database server - and package these up into separate JARs (such as yourproject-sqlserver-mappings.jar and yourproject-oracle-mappings.jar), and deploy the application with one JAR or the other depending on the environment.

I did this for a client a while back -- at deployment depending on a property set in a production.properties file I changed out the hibernate.dialect in the cfg file using Ant (you can use any xml transformer). However this would only work if the Hibernate code is seamless btw both DBs i.e. no db-specific function calls etc. HQL/JPAQL has standard function calls that help ion this regard like UPPER(s), LENGTH(s) etc.
If the db implementations must necessarily be different then you'd have to do something like what #matt suggested.

I've worked on an app that supports a lot of databases (Oracle, Informix, SQL Server, MySQL). We have one configuration file and one set of mappings. We use jndi for the database connection so we don't have to deal with different connection URLs in the app. When we initialize the SessionFactory we have a method that deduces the type of database from the underlying connection. For example, manually get a connection via JNDI and then use connection.getMetaData().getDatabaseProductName() to find out what the database is. You could also use a container environment variable to explicitly set it. Then set the dialect using configuration.setProperty(Environment.DIALECT, deducedDialect) and initialize the SessionFactory as normal.
Some things you have to deal with:
Primary key generation. We use a customized version of the TableGenerator strategy so we have one key table with columns for table name and next key. This way every database can use the same strategy rather than sequence in Oracle, native for SQL Server, etc.
Functions specific to databases. We avoid them when possible. Hibernate dialects handle the most common ones. Occasionally we'll have to add our own to our custom dialect classes, .e.g. date arithmetic is pretty non-standard, so we'll just make up a function name and map it to each database's way of doing it.
Schema generation - we use the Hibernate schema generation class - it works with the dialects to create the correct DDL for each type of database and forces the database to match the mappings. You have to be aware of the keywords for each database, e.g. don't try to have a USER table in Oracle (USERS will work), or a TRANSLATION table in MySQL.

There is a table mapping the differences between Oracle and SQLServer here: http://psoug.org/reference/sqlserver.html
In my opinion the biggest pitfalls are:
1) Dates. The functions and mechanics are completely different. You will have to use different code for each DB.
2) Key generation - Oracle and SQLServer use different mechanics and if you try to avoid the "native" generation altogether by having your own keys table - well, you just completely serialized all your "inserts". Not good for performance.
3) Concurrency/locking is a bit different. Parts of the code that is performance sensitive will probably be different for each DB.
4) Oracle is case sensitive, SQLServer is not. You need to be careful with that.
There are lots more :)
Writing SQL code that will run on two DBs is challenging. Making it fast can seem nearly impossible at times.

Related

ORM - Are DDL scripts required?

Answer says, not to trust hibernate.hbm2ddl.auto setting for production.
My understanding of using ORM:
1) To avoid designing & normalising DB schema at database layer(say RDBMS). In mongoDB world, ODM is used.
2) To avoid embedding SQL query language in code(say java).
3) To just think about storing and retrieving objects(in OOP sense)
Running DDL scripts breaks the purpose of using ORM tool and looks similar to JDBC approach except it provides the SQL dialect for vendor specific database.
For production, Can running of DDL scripts mandatory for safety?
Running DDL scripts manually breaks the purpose of using ORM tool.
No, it does not.
An Object-Relational Mapping tool is tool that helps translate data from your tables into objects that you can use in your object-orianted programming language - it has nothing to do with database administration.
Hibernate can generate a DDL based on what your classes look like right now, but it has no sense of history.
If all you're doing is adding new columns or tables you'll probably be fine but the minute you rename a column you're out of luck because Hibernate will see the old column and won't find a mapping to it so it will remove it and then create a new column using the new name. If you have a non-null requirement on that column you're screwed because you can't tell Hibernate what the default value is (well, there's a hack but please don't do this.)
You're also very limited in how you can change the types of columns - if the contents of the column can't be translated automatically by the database you're out of luck.
As an example we switched our databases from storing UUIDs in binary to storing it as a VARCHAR a while back and we had to manually convert them from binary to hexadecimal notation becasue MySQL can't do that automatically - you'd be properly screwed if you tried to do that with Hibernate's auto-DDL.
There's also no way of telling Hibernate where to create indexes - you'll get an index on each primary key column but if you want extra indexes you'll have to add these manually.
The DDL auto-generation of Hibernate is good for validating that your classes map correctly to your tables, but it should never be used to alter your production databases.
So to answer your question:
For production, does manual run of DDL scripts mandatory for safety?
Yes! And I recommend you use a management tool like Liquibase or Flyway to aid with it.
Yes, they are required. If you want to work efficiently that is.
Running DDL scripts manually breaks the purpose of using ORM tool
No it doesn't. ORM stands for Object Relational Mapping, meaning it maps the relational data of the RDBMS to Objects. Nowhere does it imply that the database schema must be changed by the ORM, even though the possibility exists (and works in very simple cases).
Besides you're not going to be running anything manually. There are database migration/refactoring products like Flyway and Liquibase that attempt to solve the problem of a database schema changing over time. They're also separate products, so you don't need to care whether you're using Hibernate or some other method of data access. They also try to provide some amount of transactionality, meaning you can revert a change to the schema in some cases.
In any non-trivial project one would try to make sure they can improve the database without being permanently locked into a legacy schema, as well as making incredibly sure that the data stays safe. A proper tool designed for that purpose makes it a lot easier, an ORM's half-baked mechanism does not.

Can you run hibernate without a database set up?

I am currently working on an application that uses hibernate as its ORM; however, there is currently no database set up on my machine and I was wanting to start running some tests without one. I figure since hibernate is object/code based that there must be a way to simulate the DB functionality.
If there isn't a way to do it through hibernate, how can this be achieved in the general case (simulation of database)? Obviously, it wont need to handle large amounts of data, just testing functionality.
Just use an embedded DB like Derby
Maybe you could also try to use an ODBC-JDBC bridge and connect to an Excel or Access file, on Windows.
Hibernate is an object-relational mapping tool (ORM). You can't use it without objects and a relational database. Excluding either one makes no sense.
There are plenty of open source, free relational databases to choose from:
MySQL
PostgreSQL
Hypersonic
Derby
MariaDB
SQLite
You're only limited by your ability to download and install one.
Other options are using in-memory database like H2 / hsqldb
I assume you have hidden all the ORM calls behind a clean interface.
If you did, you could simply write another implementation of that interface backed by a Map that caches your objects.
You could then utilize this in your test environment.
But I have to agree with #duffymo, you should just go through the 'first pain' and set up a proper working enviroment.
I'm using H2. One of its major advantages is the use of dialects that simulate the behaviour of the more common DBs. For example - I'm using PostgreSQL and I define the dialect for Hibernate to be PostgreSQL. I'm using it for my integration tests - in each test I create the data that fits my scenario for this test, which is then erased pretty easily. No need to rollback transactions or anything.

Hibernate and Multi-Tenant Database using Schemas in PostgreSQL

Background
I am working on a future multi-tenant web application that will need to support thousands of users. The app is being built on top of the Java based Play! MVC Framework using JPA/Hibernate and postgreSQL.
I watched Guy Naor's talk on Writing Multi-tenant Applications in Rails in which he talks about a few approaches to multi-tenancy (data isolation decreases as you go down the list):
Each customer has a separate database
One database with separate schemas and tables (table namespaces) for each customer.
One database with 1 set of tables with customer id columns.
I settled on approach #2, where a user id of some sort is parsed out of a request and then used to access that users tablespace. A postgres SET search_path TO customer_schema,public command is given before any query is made to make sure the customer's tables are the target of a query. This is easily done with #Before controller annotations in controller methods in Play! (this is the approach Guy used in his rails example). The search_path in postgres acts exactly like the $PATH does in an OS; awesome!
All this sounded great, but I immediately ran into difficulties in implementing it on top of a JDBC/Hibernate/JPA stack because there doesn't seem to be a way to dynamically switch schemas at runtime.
The Problem
How do I get either JDBC or Hibernate to support dynamically switching postgres schemas at runtime?
It seems database connections are statically configured by a connection factory (see: How to manage many schemas on one database using hibernate). I have found similar questions with similar answers of using multiple SessionFactorys per user, but since I understand SessionFactorys are heavy weight objects so it's implausible that you could support hundreds of users, let alone thousands of users, going this route.
I haven't committed myself completely to approach #2 above, but I haven't quite abandoned it for approach #3 quite yet either.
You can execute the command
SET search_path TO customer_schema,public
as often as you need to, within the same connection / session / transaction. It is just another command like SELECT 1;. More in the manual here.
Of course, you can also preset the search_path per user.
ALTER ROLE foo SET search_path=foo, public;
If every user or many of them have a schema that matches their user name, you can simply go with the default setting in postgresql.conf:
search_path="$user",public;
More ways to set the search_path here:
How does the search_path influence identifier resolution and the "current schema"
As of Hibernate 4.0, multi-tenancy is natively supported at the discriminator (customerID), schema, and database level. See the source code here, and the unit test here.
The difficulty is that, while the unit test's file name is SchemaBasedMultitenancyTest, the actual MultitenancyStrategy used is Database. I can't find any examples on how to make it work based on schema, but maybe the unit test will be enough to go on...
While sharding by schema is common, see this post from the Apartment gem authors covering some drawbacks.
At Citus, we shard via option #3 listed above, and you can read more in our use-case guide in the Documentation.

JPA/Hibernate support for migration?

I'm currently working on a desktop application using JPA/Hibernate to persist data in a H2 database. I'm curious what my options are if I need to make changes to the database schema in the future for some reason. Maybe I'll have to introduce new entities, remove them or just change the types of properties in an entity.
Is there support in JPA/Hibernate to do this?
Would I have to manually script a solution?
I usually let Hibernate generate the DDL during development and then create a manual SQL migration script when deploying to the test server (which I later use for UAT and live servers as well).
The DDL generation in Hibernate does not offer support for data migration at all, if you only do as much as adding a non-null field, DDL generation cannot help you.
I have yet to find any truely useful migration abstraction to help with this.
There are a number of libraries (have a look at this SO question for examples), but when you're doing something like splitting an existing entity into a hierarchy using joined inheritance, you're always back to plain SQL.
Maybe I'll have to introduce new entities, remove them or just change the types of properties in an entity.
I don't have any experience with it but Liquibase provides some Hibernate Integration and can compare your mappings against a database and generate the appropriate change log:
The LiquiBase-Hibernate integration records the database changes required by your current Hibernate mapping to a change log file which you can then inspect and modify as needed before executing.
Still looking for an opportunity to play with it and find some answers to my pending questions:
does it work when using annotations?
does it require an hibernate.cfg.xml file (although this wouldn't be a big impediment)?
Update: Ok, both questions are covered by Nathan Voxland in this response and the answers are:
yes it works when using annotations
yes it requires an hibernate.cfg.xml (for now)
There are two options:
db-to-hibernate - mirror DB changes to your entities manually. This means your DB is "leading"
hibernate-to-db - either use hibernate.hbm2ddl.auto=update, or manually change the DB after changing your entity - here your object model is "leading"

Hibernate/JPA DB Schema Generation Best Practices

I just wanted to hear the opinion of Hibernate experts about DB schema generation best practices for Hibernate/JPA based projects. Especially:
What strategy to use when the project has just started? Is it recommended to let Hibernate automatically generate the schema in this phase or is it better to create the database tables manually from earliest phases of the project?
Pretending that throughout the project the schema was being generated using Hibernate, is it better to disable automatic schema generation and manually create the database schema just before the system is released into production?
And after the system has been released into production, what is the best practice for maintaining the entity classes and the DB schema (e.g. adding/renaming/updating columns, renaming tables, etc.)?
It's always recommended to generate the schema manually, preferably by a tool supporting database schema revisions, such as the great Liquibase. Generating the schema from the entities is great in theory, but were fragile in practice and causes lots of problems in the long run(trust me on this).
In productions it's always best to have manually generated and review the schema.
You make an update to an entity and create a matching update script(revision) to update your database schema to reflect the entity change. You can create a custom solution(I've written a few) or use something more popular like liquibase(it even supports schema changes rollbacks). If you're using a build tool such as maven or ant - it's recommend to plug the db schema update util into the build process so that fresh builds stay in sync with the schema.
Although disputable, I'd say that the answer to all 3 questions is: let hibernate automatically generate the tables in the schema.
I haven't had any problems with that so far. You might need to clean some field up manually from time to time, but this is no headache compared to separately keeping track of DDL scripts - i.e. managing their revisions and synchronizing them with entity changes (and vice-versa)
For deploying on production - an obvious tip - first make sure everything is generated OK on the test environment and then deploy on production.
Manually, because:
Same database may be used by different applications and not all of
them would be using hibernate or even java. Database schema should
not be dictated by ORM, it should be designed around the data and
business requirements.
The datatypes chosen by hibernate might not be best suited for the application.
As mentioned in an earlier comment, changes to the entities would require manual intervention if data loss is not acceptable.
Things such as additional properties (generic term not java
properties) on join tables work wonderfully in RDBMS but are
somewhat complex and inefficient to use in an ORM. Doing such a
mapping from ORM -> RDBMS might create tables that are not
efficient. In theory, it is possible to build the exact same join
table using hibernate generated code, but it would require some
special care while writing the Entities.
I would use automatic generation for standalone applications or databases that are accessed via the same ORM layer and also if the app needs to be ported to different databases. It would save lot of time in by not requiring one to write and maintain DB vendor specific DDL scripts.
Like Bozhidar said, donĀ“t let Hibernate create&update the database schema.
Let your application create and update the database schema.
For java the best tool to do this is Flyway. You need to create one or more SQL files with DDL statements which are describing your database schema. These SQL files are then executed by Flyway. For more information look at the site of Flyway.
I believe that a lot of what is being discussed or argued here should also be related to if you are more confortable with the code-first or the database-first approach.
Personally, I am more intended to go for latter and, making a reference to Single Responsibility Principle (SRP), I prefer having DB specialist handling the DB and an application specialist handling the application, than having the application handling the DB. Additionally, I am of the opinion that taking too many shortcuts will work fine at the beginning but create unmanageable problems as things grow/evolve.

Categories