Hibernate+Oracle+Clob: Content of attributes get switched - oracle

Has anyone heard of this error before:
I have a Java 5 application, that uses Hibernate 3.3.2 to access an Oracle Database 10g, the JDBC driver is the Oracle light driver version 10.2.0.4.0 (the most recent version, I think).
The database access happens during a transaction that is managed via the AOP-tools of spring.
There is one database table mapped to one Java entity, the mapping is done via annotations. There are two attributes in this entity that are CLOB in the database. They are annotated according to JPA with "Lob" and are Java Strings. Everthing works fine unless both attributes have values with more than 4000 characters: After the commit the values are switched on the database, that is attribute A contains the value of attribute B and vice versa.
This is not a joke!
The Eclipse debugger tells me that the Java entity has the correct values until the transaktion closes (I did not debug into the spring transaction handling).
This error does not occur if both Clobs are annotated with the Hibernate annotation 'Type(type = "clob")' (in which case they have to be of the type java.sql.Clob and not String, of course).

I'm not 100% sure but could you try to set the connection property SetBigStringTryClob to true (see How To Handle CLOBs Easily in JDBC?).
If you are using Spring, something like this:
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
</props>
</property>

Meanwhile I found a solution to the problem: The SQL-dialect was wrong, someone set it to Oracle9 instead of the correct version, which is this:
name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"
Setting the correct SQL-dialect solves the problem :-)

I have exactly the same problem. Two CLOB on a table. On the insert only one is set and everything is fine. On the update I set the second one and after commit the values on table are swapped. Both contains more than 4000 characters. Debugged and the values on the bean are correct.
The sad thing is that i have already org.hibernate.dialect.Oracle10gDialect in my properties.
(Hibernate version 4.2.2.Final)
//UPDATE
for the moment as a workaround I have set the first column as updatable=false in the JPA annotation so that during the generation of the update query by hibernate there is only one CLOB column now. I can do this as that in this particular case I don't need to change the value after the insert, but it's not a general solution.

The only thing that worked for us was to use hql queries for the update. Each query updated a single CLOB (so we needed two separate queries):
Query query = em.createQuery("update SomeTable as someTable set value = :value where id = :id");
query.setParameter("value", value);
query.setParameter("id", id);
if (query.executeUpdate() != 1) {
throw new Exception("Value update had no effect");
}

Related

Spring-data-jdbc - How to set schema in many-to-many relationship

I am following the spring.io blog here: https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates and have a sample SpringBoot app with Book and Author entities here: https://github.com/b-sridhar/spring-data-jdbc-example.
I get the following error: No value supplied for the SQL parameter 'demobook': No value registered for key 'demobook'
And while debugging noticed the SQL query that is executed is: INSERT INTO demo.book_author (author, demo.book) VALUES (:author, :demobook) which should have been INSERT INTO demo.book_author (author, book) VALUES (:author, :book). This happens because I have the #Table("demo.book") as the annotation for the Book entity. If I remove the demo schema in the table name then the tests in BookAndAuthorsTests go through fine.
How to set the schema for the table Book?
This is a bug in the 1.0.x release. It is fixed for 1.1.
If you upgrade your spring-boot-starter-parent to 2.2.0.M5 you'll get the spring-data-jdbc version 1.1.0.RC2 which contains the fix.
With that fix table names in #Table annotations do work as well as the approach of having the NamingStrategy return a schema.
Note: that your configuration then needs to extend AbstractJdbcConfiguration instead of JdbcConfiguration.
Another note: Your example project then chokes because the AuthorRef needs an explicit mapping to the table BOOK_AUTHOR.
I'll leave a PR in a second.

How do I execute named queries from a JPA EntityListener?

I have a requirement to set a date_updated value in my database for each row when that row is updated. Let's call the entity that I'm working with Order, which has a corresponding orders table in the database.
I've added the date_updated column to the orders table. So far, so good.
The #Entity Order object that I'm working with is provided by a third party. I do not have the ability to modify the source code to add a field called dateUpdated. I have no requirement to map this value to the object anyway - the value is going to be used for business intelligence purposes only and does not need to be represented in the Java entity object.
My problem is this: I want to update the date_updated column in the database to the current time each time an Order object (and its corresponding database table row) is modified.
Constraints:
We are using Oracle, Spring, JPA and Hibernate
I cannot use Oracle triggers to update the value. We are using a database replication technology that prevents us from using triggers.
My approach thus far has been to use a JPA EntityListener, defined in xml, similar to this:
<entity-mappings xmlns="....">
<entity class="com.theirs.OrderImpl">
<entity-listeners>
<entity-listener class="com.mine.listener.OrderJPAListener" />
</entity-listeners>
</entity>
</entity-mappings>
My listener class looks like this:
public class OrderJPAListener {
#PostPersist
#PostUpdate
public void recordDateUpdated(Order order) {
// do the update here
}
}
The problem I'm having is injecting any sort of persistence support (or anything at all, really) into my listener. Because JPA loads the listener via its methods, I do not have access to any Spring beans in my listener class.
How do I go about injecting an EntityManager (or any Spring bean) into my listener class so that I can execute a named query to update the date_updated field?
How do I go about injecting an EntityManager (or any Spring bean) into
my listener class so that I can execute a named query to update the
date_updated field?
As noted above JPA 2.1 supports injecting managed beans to an Entity Listener via CDI. Whether or not Spring supports this I am not sure. The folloiwng post proposes a Spring specific solution.
https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
A possible alternative approach would be however to override the SQL generated by Hibernate on an update which is possible as detailed below.
https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/querysql.html#querysql-cud
This would be straightforward if you had the source as you would just need to add the #SQLUpdate annotation and tag on the additional date_update column. As you don't however you would need to look at redefining the metadata for that Entity via an xml configuration file and defining the sql-update statement as outlined above:
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/xml-overriding.html#xml-overriding-principles-entity
Since JPA 2.1 Entity Listeners are CDI managed. Have you tried using #PersistenceUnit annotation? Are you using JTA transaction type?
Otherwise you could use Persistence.createEntityManagerFactory within the Listener class to retrieve the Persistence Context.

Hibernate generates too long identifiers for Oracle

We are using JPA with Hibernate 4.3.8 and Oracle 11. Our entities doesn't have explicit DB identifier names declared in annotations and so we rely upon Hibernate to generate them correctly.
For MySQL it works properly but after we had switched to Oracle then we've encountered couple of the problems.
One of them is that Hibernate-generated schema contains identifiers longer than Oracle supports. We thought that Oracle10gDialect handles it but it seems we were wrong.
What is the best approach to add support of Oracle to our application? Must we explicitly declare all the database tables/columns/indexes... in annotations (#Table, #Column...)? Shouldn't it be Hibernate who takes a care of this dialect-specific task?
Another problem is that Hibernate also doesn't escape the keywords (eg. column name code must be escaped in Oracle). What if we decide to support another database in the future? Must we choose all the identifier names so that all of them suit for every DB? This seems to be very overhelming. (Note that the property hibernate.globally_quoted_identifiers can solve it partially but then #UniqueConstraint columns doesn't match.)
Or maybe... does Eclipselink handle this?
In such cases you can use Hibernate's NamingStrategy prepared for Oracle.
In simple words: NamingStrategy tells Hibernate how to generate names for columns or tables.
You can provide oracle-aware NamingStrategy as I do for each of my Oracle/Hibernate projects.
Here is sample JPA configuration:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
...
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.ejb.naming_strategy" value="com.mycompany.OracleNamingStrategy"/>
<entry key="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
...
</map>
</property>
</bean>
Here is the NamingStrategy I have been using for many projects:
https://code.google.com/p/hibernate-naming-strategy-for-oracle/source/browse/trunk/src/de/schauderhaft/hibernate/OracleNamingStrategy.java
look at smart abbreviating method that guarantees to produce Oracle-compliant name:
public static String abbreviateName(String someName) {
if (someName.length() <= MAX_LENGTH)
return someName;
String[] tokens = splitName(someName);
shortenName(someName, tokens);
return assembleResults(tokens);
}
There are many articles about applying NamingStratety with Hibernate, for example:
1.
http://www.petrikainulainen.net/programming/tips-and-tricks/implementing-a-custom-namingstrategy-with-hibernate/
2.
http://sudhirmongia.blogspot.com/2010/08/naming-strategy-in-hibernate.html
I hope this helps.

Hibernate's saveOrUpdate ignores not-null column property

I have a mapping file that specifies a given column as not-null="true". This is a mistake since the table's column is set to NULL on the Oracle database. But we did not notice that until now, more than an year after creating the mapping file, because Hibernate have been "ignoring" this. Is that possible?
To make it clearer. On the database:
CREATE TABLE db.my_table
(...)
my_column NUMBER(10,0) NULL,
(...)
On the mapping file:
<column name="MY_COLUMN" precision="10" scale="0" not-null="true">
Then on the Java code:
getHibernateTemplate().saveOrUpdate(myEntity);
getHibernateTemplate().flush();
This code is WORKING on our environment. Has always been. But some clients have had issues of ot-null property references a null or transient value and when I debugged the code it didn't make any sense. This code should never been able to run, as far as I know.
Of course it's simple to solve the clients problems, I just have to correct the mapping file so it represents my entity properly. But the real issue here is why haven't Hibernate complained about it?
I've asked some other engineers here with more experience on Hibernate but none of them have ever seen this.
So, can anyone gimme a hint?
EDIT: Just want to stress that both our test environment and my client's are running the exact same code, and in both cases the myEntity object has the myColumn property set to NULL. So, what puzzles me is why it does not yield any exception here on our environment.
It is absolutely correct behaviour.
The not-null attribute has two meanings:
support schema exporting tools
check the Entity in runtime (i.e. do not check database column setting)
See: 5.1. Mapping declaration, extract:
The mapping document also contains some extra optional attributes and
elements that affect the database schemas exported by the schema
export tool (for example, the not-null attribute).
And 5.1.11. Property, extract:
not-null (optional): enables the DDL generation of a nullability
constraint for the columns.
So, if your clients run some code, which tries:
getHibernateTemplate().saveOrUpdate(myEntity);
while the myEntity is missing some property set as not-null="true" it is correct in throwing a runtime exception. While in your test environment you most likely always set the property to some not null value.
And there is an advantage even. The DB and App are loosely coupled. So if needed, you can make more constraints on App side, while not touching the DB (e.g. you are not allowed)
I had exactly the same problem:
In my hibernate mapping file I had set not-null="true" for a special column.
On my development machine I could persist null values without any exceptions. On the customers machine we always received a PropertyValueException / DataIntegrityViolationException.
This was a dangerous behavior. Manual and automatic tests would not fail.
Solution:
On my development machine I hat to set the property hibernate.check_nullability to true. Only then I also got the exceptions on my development system.
Conclusion
This strange behavior could come from adding the hibernate validator to the classpath. This turns check_nullability to false.
See this related question: How to Enable Spring Validation
Somehow this only applies on my dev-system and not in production. This might root from a different dependency loading within different application servers.

Spring Roo Oracle and Underscore

I have a question concerning spring roo and databases.
I have a field called personName, in oracle to column is create as person_Name
I there a way to avoid the underscore. I suppose naming my column personname would fix this, but can I ask spring not to add the underscore ?
If you need a general solution (instead of "fixing" some single points (abaloghs answer)), you can specify a Naming Strategy for your JPA provider.
For an example see: JPA (Hibernate) and custom table prefixes
Roo by default refers to the JPA implementation to determine column names. You can override the defaults with the --column property:
entity --class Foo
field string --fieldName FooBar --column fooBar
Bonjour,
by the way, I do not think that it is possible to reverse engineer a database with underscores in table names :
the corresponding domain classes will be created and compiled since Java accept undersocres in class names
the tests will be performed without raising any issue
everything will be scaffold for the GUI
you will succesfully deploy it on tomcat and your application page will show up in your browser
You may fill the form to create a new instance of your object
But if you click on SAVE --> internal error
If you have a look at the tomcat log, you will fid the well known exception : javax.servlet.jsp.JspTagException: No message found under code ...
The reason is that your class name has been truncated in the message_xx.properties files.
Everything before the underscore is dropped and thus, no message is found in order to display that your record has been successfully saved.
It would be nice that the ROO shell raise an error when the jpa entity is created and not at runtime ...

Resources