In Oracle we can create an update query that will return the updated record using the RETURNING clause.
Is there similar functionality in Hibernate?
Apart from database-generated values there is obviously no need for Hibernate to return the updated instance because the object passed to Session.saveOrUpdate() is the updated instance. Database-generated values (sequence, trigger, defaults, etc.) will be set after Session.saveOrUpdate if they are accordingly annotated (or defined in a XML mapping file).
For identifier values use the JPA #javax.persistence.GeneratedValue annotation in conjunction with the JPA #javax.persistence.Id annotation. For simple properties use the native Hibernate #org.hibernate.annotations.Generated annotation (afaik there is no according JPA annotation).
How generated identifier values are retrieved by Hibernate depends on the generation strategy and/or the database dialect. For simple properties Hibernate executes an additional SELECT by id statement after the INSERT or UPDATE.
Related
1) When does Hibernate Envers create or alter the audit tables in the schema when there is a new Entity or column that is annotated with #Audited?
2) Is there a way to log the mysql commands that are called when there is a new audit table or column added?
When does Hibernate Envers create or alter the audit tables in the schema when there is a new Entity or column that is annotated with #Audited?
Technically Hibernate Envers does not do this at all, this entire step is handled by Hibernate ORM proper.
During bootstrap of Hibernate ORM, the following steps occur:
ORM gathers all entity mappings, those defined in XML and annotated classes. ORM takes all these representations and builds what we call a boot-model representation of the entities.
Envers implements a special hook that ORM calls into immediately after the boot-model has been prepared but before the runtime model is built which ORM uses thereafter. This hook allows Envers to parse the boot-model in conjunction with the annotated java classes and it creates additional entity mappings for ORM that supplement what was built in (1). These mappings are currently provided to ORM has additional Hibernate HBM XML mappings.
If the hook produces any additional HBM XML mappings, Hibernate ORM integrates those directly by converting them into boot-model representations as well.
Right before Hibernate ORM converts this boot-model into the runtime-model representation, ORM builds a database representation of the mappings. It is at this point that the database model is used during the Schema Migration (if enabled) to validate/update/create the schema to match the database model representation.
Is there a way to log the mysql commands that are called when there is a new audit table or column added?
There are several ways to accomplish this, some are easier than others of course.
For example, you could enable Hibernate SQL logging, configure those entries to be written to a special named file using your logging API of choice and then ship those logs off for post-processing on defined intervals.
You could also consider using something more standalone such as Debezium that is capable of monitoring database changes at the transaction/archive/oplog/binlog level and for certain connectors exposes a Kafka topic that specifically stores DDL changes.
Hibernate-envers is using interceptors to insert changes into audition-tables. They are called right before the transaction is committed to the database.
The question is a little bit unclear, if you say mysql-commands I guess you mean update-queries like CREATE TABLE and CREATE COLUMN. By default, enver is reporting violations against the schema. I can imagine that - if you expose the audition-tables as hibernate-entitys aswell - a hbm2ddl might create those create-table and create-column update-queries.
After all I suggest to use the single-source-of-version-of-truth concept (SSOVOT) and failfast (FF) and dare the database as the single-point-of-faliure (SPOF).
The wording problem
Yes, the hibernate-plugin is called enver, but from an scientific pov a enver(entity-version) is only the version-property marked with #Version in the entity. The correct name is audition because you historically log all changes to the table in the database.
In case of "change entity tables" having rows already.
First to say is that every payload-column in entity-tables is nullable, you must add a column in the audition-table it has by default a null value. But if the genuine table does not allow to have null-values in the colmn the audition is broken! This will lead to unexpected problems. This means that the automated replication of genuine-columns to audited-columns must be an process of reconstruct schema AND DATA.
I'm trying to replicate the behavior of "update versioned" of Hibernate in Openjpa:
em.createQuery("update versioned MyEntity m set m.otherEntity=null where m.otherEntity=:otherEntity).setParameter("otherEntity", otherEntity).executeUpdate();
I tried the same query in openjpa but i'm getting a error for this query (it takes the "versioned" as a alias), so its clearly a HQL feature.
Hibernate spec:
In keeping with the EJB3 specification, HQL UPDATE statements, by default, do not effect the version or the timestamp property values for the affected entities. However, you can force Hibernate to reset the version or timestamp property values through the use of a versioned update. This is achieved by adding the VERSIONED keyword after the UPDATE keyword.
so HQL has the option to use the update versioned to reset version
however in OpenJpa:
Bulk update maps directly to a database update operation, bypassing optimistic locking checks. Portable applications must manually update the value of the version column, if desired, and/or manually validate the value of the version column.
The last few days I've rolled up my sleeves and dug into Hibernate for the first time. I was very surprised to learn that Hibernate's default behavior is to actually drive the DDL of the database itself:
<property name="hbm2ddl.auto">create</property>
or
<property name="hbm2ddl.auto">update</property>
This is opposite of what I'm used to, where someone (usually a DBA) creates the database structure: the schemas, the table, the key constraints, the indexes, triggers, etc; and then I (the developer) code my app to abide those constraints.
This raises a few similarly-related questions:
How are indexes created/maintained in conjunction with a Hibernate-based app? Pick your favorite relational DB - MySQL, Postgres, Oracle, anything. Do you specify indexes through Hibernate (and if so, how), or do you have to specify them in the DB (and if so, how do you get Hibernate to honor such indexes and not overwrite them)?
Same question as #1 above, but with multi-column keys instead of indexes.
How do you specify column order in Hibernate? Is it just based on the order of the Java fields inside the entity? What about columns that Hibernate adds (such as when doing joins or implementing inheritance strategies)?
If I manuall install a trigger on a table that Hibernate created, how do I prevent Hibernate from overwriting/deleting it?
How do I specify what DB/schema a Hibernate table gets created in?
Thanks in advance!
You can use #Index annotation on your entity field
Please see this question / answer: How to define index by several columns in hibernate entity?
Yes it's just based on the order of Java fields in the entity
You can set hbm2ddl.auto to "validate" to make it just validate your schema, without making any updates.
You can use #Table(name = "..") annotation to specify custom name for your entity/table
I was experimenting with eclipselink. I am trying to update an existing entity in database. The JPA entity only has public fields and fields are annotated with JPA annotation. The code loads an entity using EntityManager.find().
The code creates an instance of JPA entity, assigns value to public fields of the entity and invokes EntityManager.merge(entity) method. Eclipselink does not update database record. I enabled log to see whether Eclipselink issues SQL statement or not.
Eclipselink does not issue any update statement. Does this mean that even if I use field persistence, I can not assign value to public fields of the entity instead of using setter method?
Thanks,
Chir
Weaving introduces some optimizations such as lazy onetoone and manytones and change tracking. The only way these can work is if you use the accessor method on the entity, but if that isn't an option, you can turn them off as needed. See
http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_changetracking.htm
For details on change tracking.
I use JPA 2 with Hibernate Entity Manager 3.6.4. Once I have marked my entities with various annotations (#Entity, #MappedSuperClass etc), I put in my persistence.xml file the default schema to use (hibernate.default_schema property).
I know it's possible to create automatically the objects contained in the schema.
But is it possible to create the schema itself automatically and then create the objects it contains ?
EDIT :
I use this parameter too : hibernate.hbm2ddl.auto, to tell Hibernate to create the schema if it doesn't exists yet. No luck, Hibernate doesn't create it !
I have googled a little bit and find this post : Hibernate hbm2ddl won't create schema before creating tables.
The fact that Hibernate does not create a schema before creating table is a bug. Other database suffer from this situation : H2, Postgresql etc.
This bug is planned to be fixed with 5.0.0 release of Hibernate.
So, for now, the only workaround is to create the schema by yourself, either manually or by a mean offered by your database vendor, since Hibernate can't do it itself :\
I managed to build a workaround that uses the hbm2ddl default flow.
Since it always calls the "database-object" drop statements BEFORE creating schema, you can do something like this:
<database-object>
<create></create>
<drop>DROP SCHEMA IF EXISTS myschema cascade; CREATE SCHEMA myschema</drop>
</database-object>
unfortunately the create clause is mandatory and sadly it's only executed AFTER schema creation, no matter what order you put it on cfg.xml, so I made it empty, that way you don't have errors trying to creating schema again (it was already created together with drop)