What to use: sql migration or entity setups in Spring/Hibernate? - java

I am little confused, when see, why most programmers use annotation-based setup for database table constraints. For example
#Column(unique=true, nullable=false)
Why do we need that, if(as I heard) in real projects mostly used SQL migrations, so you are able to create this constraints in table creations, like CREATE table... name varchar UNIQUE NOT NULL.
Do I need to setup it in both ways, or is it enough to do in SQL?
And how often SQL migrations used(Flyway, Liquibase) in projects?
Additionally, Hibernate creates unreadable constraints in database, otherwise in SQL you create understandable names of constrains.

You can choose whether to let Hibernate to manage your schema or not. If yes , the database schema will be created or updated based on the changes of the annotation mapping.
I personally will not let Hibernate to manage my database schema as I want to be exactly know what is going on with the schema changes . The hibernate documentation also suggests it somehow:
Although the automatic schema generation is very useful for testing
and prototyping purposes, in a production environment, it’s much more
flexible to manage the schema using incremental migration scripts.
while Flyway, Liquibase is the kind of incremental migration scripts tool.
Do I need to setup it in both ways, or is it enough to do in SQL? And
how often SQL migrations used(Flyway, Liquibase) in projects?
If you do not use the automatic schema generation feature , you don't need to specify unique in #Column which only has meaning in case of automatic schema generation.
For nullable , it depends on hibernate.check_nullability setting.If it is turned on and you set #Column(nullable=false) , Hibernate will help to check this column cannot be null in the application level without asking the DB to check it. But even if do not set it , the database constraint (assuming you create a non-null constraint for it in DB) will eventually check it and not allow you to save the null value

Related

How can one add constraints on existing tables via JPA / Hibernate?

I am using a Postgresql database with JPA / Hibernate. When I'm adding a constraint to a column, i.e. "nullable=false", the database column is not altered to reflect this. Deleting the table and rerunning the application does the job.
Can this be achieved with JPA/Hibernate - mechanisms only WITHOUT deleting entries or the table? Like "Try to alter the table and refuse to do so on inconsistent data"? In my application.properties, I've set
hibernate.hbm2ddl.auto=update
Any other setting seems to be deleting data and/or tables.
A working solution would be to run an ALTER TABLE script and adding a constraint annotation accordingly, but I'm not really fond of this.
It is impossible to add constraints to the existing table. Think wide about it - what if the data in the table is not satisfied with the constraint? You will get the whole application crash. So Hibernate not even trying to apply the potential harmful operation.
In general, there is the wrong way to manage database schema with hibernate. Auto-generation schema is appropriate for learning or MVP purposes but not for production. Also, SQL migration is a bad idea for many reasons. You should use a special tool for schema management: liquibase (better for me) or flywaydb

How to fix ordering in the generated table in JPA. Do we have some workaround without any framework?

Hibernate generates columns in alphabetical order. My requirement is to maintain proper order like below :
id
title
subtitle
created_on
and the table is getting created like this :
id
created_on
subtitle
title
Do we have some workaround without any framework?
Hibernate guide
Although the automatic schema generation is very useful for testing and prototyping purposes, in a production environment, it’s much more flexible to manage the schema using incremental migration scripts.
So create your schema yourself and manage it via an incremental migration tool like flyway or liquibase is your best option.

jOOQ: Find constraints in a specific table

While working in jOOQ-agnostic (without code generation) migrations I've encountered a situation in which I need to check if a constraint (unique, foreign key) already exists in the database in order to complete further operations.
What I've tried so far is to run the drop and try to catch the exception, but it fails the transaction and stops following migrations from happening
dsl.alterTable(table).dropConstraint(constraintName).execute();
...
>> ERROR: constraint "t_client_name_unique" of relation "t_client" does not exist
Setup:
Spring
jOOQ without code generation
FlywayDB as migrations library
Postgres
Future solutions (not available in jOOQ 3.12)
For jOOQ 3.13+, we're investing heavily in supporting more such migration scenarios. In the future, we'll support some vendor agnostic information_schema style views that produce this kind of meta information for all databases: #8301
Another feature that could help you here immediately would be native DROP CONSTRAINT IF EXISTS support: #9557. You could, of course, use plain SQL to run this particular statement on PostgreSQL, until #9557 is available
A solution right now
Alternatively, in your case, since you're only using PostgreSQL, you could do this directly by querying PostgreSQL's information_schema. You could generate information_schema tables and then run this query:
select *
from information_schema.table_constraints
where constraint_schema = :constraint_schema
and constraint_name = :constraint_name

Working with microservices. Hibernate or Scripts

What is the best approach for database creation and relationship management when working with microservices?Hibernate or scripts, as i feel it shouldn't be the responsibility of microservices to create a database
As already pointed by #Vadim in the comment it ultimately it is the desginer's or developer's job to decide what to use.
My two cents from experience, in long run it is always good to use schema generation scripts and there are lots of opensource libraries available.
For instance in java we have Liquibase and Flyway.
The reason why I am saying this is, your DB will undergo lot of changes in long run. Hibernate can easily handle creating and modifying table and column changes, but sometimes for example when you add a new column you may want to fill the existing records for which you may need to write custom sqls.
Similarly from time to time you may want to update records from back-end which is difficult to achieve using hibernate.
I have observed that DB creation generally is part of pre-deploy scripts and schema generation happens during application startup.
My advise is to use some schema generation tool for schema migration and use hibernate for schema validation so that the two remain in sync.

Does Hibernate have to drive database design?

I spent all of yesterday reading various articles/tutorials on Hibernate and although I am blown-away by how powerful it is, I have one major concern with it.
It seems that the standard practice is to allow Hibernate to design/generate your DB schema for you, which is a new and scary concept that I am choking on. From the tutorials I read, you just add a new entity to your hibernate.cfg.xml config file, annotate any POJO you want with #Entity, and voila - Hibernate creates the tables for you. Although this is very cool, it has me wondering about a handful of scenarios:
What if you already have a DB schema and the one Hibernate wants to generate for you does not conform to it? What if you have a crazy DBA that refuses to budge on the pre-defined (non-Hibernate) schema?
What if you have reference tables with tens of thousands of records in it (like all the cities in the world)? Would you have to instantiate and save() tens of thousands of unique POJOs or is there a way to configure Hibernate so it will honor and not overwrite data already existing in your tables?
What if you want to do perf tuning on your schema/tables? This includes indexing, normalizing above and beyond what Hibernate creates automatically?
What if you want to add constraints or triggers to your tables? Indexes?
I guess at the root of this is the following:
It looks like Hibernate creates and forces a particular schema/config on your DB. I am wondering how this agenda will conflict with our platform standards, our DBA philosophies, and our ability to perf tune/tweak tables that Hibernate interacts with.
Thanks in advance.
I think you're attributing too much power to Hibernate.
Hibernate does have an idiom that may influence database implementation.
Hibernate does not generate a schema for you unless you ask it to do so. It's possible to start with an existing schema and map it to Java objects using Hibernate. But it might not be possible or optimal if the schema conflicts with Hibernate requirements.
If the DBA won't budge - as they shouldn't - or Hibernate can't accomodate you, then you have your answer: you can't use Hibernate.
Your DBA might consent, but your app might find that the dynamic SQL that's generated for you by Hibernate isn't what you want.
Fortunately for you, it's not the only game in town.
I don't think implementations have to be all or none. If you use simple JDBC to access reference data, what's the harm?
Database design considerations should be independent of Hibernate. Constraints, triggers, normalization, and indexes should be driven by business needs, not your middleware choices.
If you don't have a solid object model, or the schema can't accomodate it, then you should reconsider Hibernate. There's straight JDBC, stored procedures, Spring JDBC, and iBatis as alternatives.
Hibernate comes with a default way to map objects to tables - like several tools/libraries, it favours convention over configuration for simplicity.
However, if you want to map the entities to database tables differently, you can explicitly tell Hibernate how these are mapped (from simple attributes such as changing the table name, through to redefining the foreign-key relationships between related entities and how this is persisted).
If you do this correctly, you don't need to instantiate and save existing data, as this would be pointless - the database already contains the information about the entities in exactly the form that Hibernate understands. (Think about it - to load and then immediately save an entity should always be a no-op, and so can be skipped altogether.)
So the short answer to your question is "no". If you don't care for designing tables, you can let Hibernate adopt a reasonable default. If you do want to design your schema explicitly though, you can do this and then describe that exact schema to Hibernate.
As someone who's worked on java and hibernate in the enterprise for a long time, I have seen very few projects which use this capability. You'll see some build tools and other things do this, but for a real enterprise app, i've never seen this.
Most DBA's won't let the application user create tables. They rely on a privileged user to do those things, and the user that the app connects as would have r/w privs on the data but not the schema itself.
As a result, you write the SQL yourself, and you do the hibernate mappings to match. It doesn't mean your object design won't influence your SQL, but you should still always create your schema upfront.
No. You can use hibernate tools to generate the entities from existing database.
There are 2 ways you can go about in using Hibernate. If you have good DBA or database designer, then it is better to design the database and then map it into hibernate.
On the other hand if you don't have DBA and have good developer then let Hibernate generate Database for you.
The concept behind Hibernate is to map Database and the Objects. So it is called as ORM (Object-Relational Mapping) tool.
Read here for Object Relational Impedance.
This is the preferred way for a quick'n dirty prototype or a simple tutorial, but it's far from being the preferred way for any production application. I largely prefer designing the database independently, using scripts to generate the schema, tables, views, indexes, etc., and map the schema to entities.
As long as the mapping finds the tables and columns in the database, everything is fine.
As soon as you have data in your database and the schema must change, you'll have to write migration scripts anyway. You can't just drop everything and restart from scratch. The tutorials are written for developers starting with Hibernate and who must discover Hibernate as quick as possible, without dealing with complex SQL scripts.
What if you already have a DB schema ...
I don't know where you get that impression. Hibernate can use existing schema. It is quite flexible.
What if you have reference tables ...
Make the relationship LAZY, and it won't load automatically. Only changed object will be saved.
What if you want to do perf tuning ...
Just don't use the generated schema. It is just a starting point. You can customize as you need.
What if you want to add constraints or triggers to your tables? Indexes?
Some as above.
You can use hibernate with an existing database schema.
You can use various annotations to map to existing tables and columns, for example:
#Table(name = "dbschema.dbTable") - should be placed before your class file to map it
#Column(name = "colName") - to map a column
Just be sure that the hibernate is configured with this option:
hibernate.hbm2ddl.auto=update
If you set this to create it will create the schema, so do not do this in your case.
Use hibernate/jpa when appropiate. A common practice when designing apps is to extract the draft and alter it manually after needs (indices etc). However, it will be a pain for you if you change the db layout from hibernate way to do things. Lots of the beauty of JPA will be lost. For tasks which require heavy performance tuning and full control - just go for reguar jdbc.
Some answers:
A. It is possible to add an index annotation : see the table annotation.
B. If you have reference tables, you may choose to have lazy fetching or eager fetching (i.e - if your tables represent a person and a its books - whether to load a person without its book, or with its books)
C. Hibernate can be used to work on existing schema. The schema might not be trivial to work with , but as other have said, you should design db only according to business needs, and not according to framework conventions
D. I would like to encourage you also to read what hibernate does "under the hood" - it uses lots of usage of proxies, which hurts performance, you must understand well the scope of session , and the usages of 1st level and 2nd level cache .
E. Following what I wrote at section D - working with triggers will cause your DB to change "under the hood" when it comes to hibernate. Consider a case where updating a record will create (using a trigger) an entry in some archiving table , and let's say this table is also annotated via hibernate - your hibernate caching will not be aware of the change that happend outside of the application scope.
F. It is important to me to state that I'm not against Hibernate, but you should not use it for all solutions, this is a mistake I did in the past. I now work with Spring-JDBC and I'm quite pleased (for our application needs it will be hard to use Hibernate, and I assume we will consider this only in the case we need to support more than one DB flavor).

Categories

Resources