Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Hibernate to 5.x #1113

Closed
asolntsev opened this issue Feb 23, 2017 · 16 comments
Closed

Upgrade Hibernate to 5.x #1113

asolntsev opened this issue Feb 23, 2017 · 16 comments
Assignees
Milestone

Comments

@asolntsev
Copy link
Contributor

Currently Play1 uses Hibernate 4.2.19 which is pretty old.
Need to upgrade to Hibernate 5.2.5 (or later).

See https://play.lighthouseapp.com/projects/57987-play-framework/tickets/1818-hibernate-need-to-be-updated-to-v435#ticket-1818-6

@asolntsev asolntsev self-assigned this Feb 23, 2017
@asolntsev asolntsev added this to the 1.5.0 milestone Feb 23, 2017
@tomparle
Copy link
Contributor

Thank you Andrei for this (among several others) improvement !

@asolntsev
Copy link
Contributor Author

@tomparle @xael-fry
Hi! Can you help me with Hibernate 5?

Can anyone tell why the third line saves BLUP, thought I didn't call any save method?

Horse existing = Horse.all().first();   // existing.bulp == null
existing.setBlup(new BLUP());
em().flush();   // why it executes "insert into BLUP (id, total) values (null, ?)" ???

@asolntsev
Copy link
Contributor Author

@tomparle @xael-fry
I found the answer. We just have to add the following property: properties.put("org.hibernate.flushMode", FlushMode.MANUAL);

to avoid auto-saving of dirty (unsaved) objects.

@flybyray
Copy link
Contributor

@flybyray
Copy link
Contributor

@xael-fry @asolntsev

I found the answer. We just have to add the following property: properties.put("org.hibernate.flushMode", FlushMode.MANUAL);

It should have a ticket in lighthouse and should be fixed for 1.4.x too. The current AUTO-FlushMode has unpredictable consequences.

@asolntsev
Copy link
Contributor Author

@flybyray @tomparle @xael-fry Actually I am not sure about my previous answer. Probably the default value AUTO of setting "org.hibernate.flushMode" is good.

Alex, do you know why HibernateInterceptor is needed? Can we remove it? Without it, the failing test JPASave becomes green.

@flybyray
Copy link
Contributor

flybyray commented May 6, 2017

@asolntsev HibernateInterceptor is some essential part of Play! JPA improvment. I think you will need it even in Hibernate 5+. Please look for the willBeSaved variable and its usage saveAndCascade.

Maybe you should look into framework/patches/hibernate-4.2.19-patch-play.patch.patch too to find an answer for failing tests.

@xael-fry
Copy link
Member

xael-fry commented May 8, 2017

I agree with @flybyray we should keep HibernateInterceptor

@asolntsev
Copy link
Contributor Author

Implemented in PR #1114

@tazmaniax
Copy link
Collaborator

Just testing my application with the new Hibernate 5.2.x support and I run into this exception below with my existing MySQL database.

I fixed the exception by adding this property "hibernate.id.new_generator_mappings=false" to the application.conf as suggested by the best answer in this StackOverflow entry, "Hibernate-sequence doesn't exist"

Looks like this could be a common situation and maybe this property should be included in the default application.conf. wdyt?

23:26:46,440 [play-thread-1] DEBUG ~ select next_val as id_val from hibernate_sequence for update
23:26:46,446 [play-thread-1] ERROR ~ could not read a hi value
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'mydb.hibernate_sequence' doesn't exist
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
	at com.mysql.jdbc.Util.getInstance(Util.java:408)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:943)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2490)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
	at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1966)
	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:353)
	at org.hibernate.id.enhanced.TableStructure.executeQuery(TableStructure.java:216)
	at org.hibernate.id.enhanced.TableStructure.access$300(TableStructure.java:46)
	at org.hibernate.id.enhanced.TableStructure$1$1.execute(TableStructure.java:138)
	at org.hibernate.id.enhanced.TableStructure$1$1.execute(TableStructure.java:126)
	at org.hibernate.jdbc.WorkExecutor.executeReturningWork(WorkExecutor.java:55)
	at org.hibernate.jdbc.AbstractReturningWork.accept(AbstractReturningWork.java:34)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:57)
	at org.hibernate.id.enhanced.TableStructure$1.getNextValue(TableStructure.java:125)
	at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40)
	at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:432)
	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:105)
	at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
	at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
	at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:840)
	at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:833)
	at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:341)
	at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458)
	at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383)
	at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193)
	at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:491)
	at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:423)
	at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:386)
	at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193)
	at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126)
	at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:172)
	at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:163)
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:74)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1435)
	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1421)
	at play.db.jpa.JPABase._save(JPABase.java:58)
	at play.db.jpa.GenericModel.save(GenericModel.java:364)
	at controllers.TaskController.addHelper(TaskController.java:452)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:538)
	at play.mvc.ActionInvoker.invoke(ActionInvoker.java:475)
	at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:469)
	at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:436)
	at play.mvc.ActionInvoker.invoke(ActionInvoker.java:159)
	at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:326)
	at play.Invoker$Invocation$1.apply(Invoker.java:319)
	at play.Invoker$Invocation$1.apply(Invoker.java:315)
	at play.db.jpa.JPA.withTransaction(JPA.java:285)
	at play.db.jpa.JPA.withinFilter(JPA.java:238)
	at play.db.jpa.JPAPlugin$TransactionalFilter.withinFilter(JPAPlugin.java:304)
	at play.Invoker$Invocation.withinFilter(Invoker.java:298)
	at play.Invoker$Invocation.run(Invoker.java:315)
	at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:303)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
23:26:46,447 [play-thread-1] WARN  ~ SQL Error: 1146, SQLState: 42S02
23:26:46,448 [play-thread-1] ERROR ~ Table 'mydb.hibernate_sequence' doesn't exist
23:26:46,483 [play-thread-1] ERROR ~ 

@asolntsev
Copy link
Contributor Author

Yes, this is because hibernate.id.new_generator_mappings=false was default in Hibernate4, but in Hibernate5 default value is hibernate.id.new_generator_mappings=true`.

At the beginning I also got similar errors and added this setting. But later I discovered that there is a better solution. I re-configured my DB to properly use autoincrement.

In your case, you use MySql which supports autoincrement feature. So you probably need to turn ``autoincrementtoON` and avoid using sequences at all.

@tazmaniax
Copy link
Collaborator

tazmaniax commented Jun 4, 2017

@asolntsev I've been using MySQL's auto increment feature from the beginning. I think the use of sequences is being activated by the combination of the @GeneratedValue annotation on Model.id and hibernate.id.new_generator_mappings=true. The default GenerationType is auto which "Indicates that the persistence provider should pick an appropriate strategy for the particular database". As MySQL auto increment is typically the default I would be surprised if the MySQL persistence provider would select sequences for identity columns but if that is case then I think that the hibernate.id.new_generator_mappings setting is the only option in my case unless the @GeneratedValue can be removed from Model.id

@asolntsev
Copy link
Contributor Author

@tazmaniax So, what you suggest?

@tazmaniax
Copy link
Collaborator

@asolntsev ok after doing some more digging I've found that the behaviour change in 5.x is not compatible with MySQL autoincrement and is explained in detail in this blog article. The author also raised a Hibernate JIRA ticket but by the sounds of it it has been rejected by the core Hibernate team for reasons unknown. The initial suggested work around is to add generator="native" to the @GeneratedValue definition, but I don't think it's feasible to make this change to the framework in a generic way that works for all cases. There is another suggested work around by the same author that involves using JPA XML metadata to override the annotation but that seems pretty heavy weight solution.

In the end I think will just stick with hibernate.id.new_generator_mappings=false. Apart from the id generator which is not needed in my case I don't think there is any other impact to the Hibernate execution and I don't need to support multiple database types requiring portable metadata.

Sorry for the distraction but maybe this is useful for someone else who comes across this :)

@asolntsev
Copy link
Contributor Author

@tazmaniax Yes, sure, it can be useful for many people.
Thank you for sharing the knowledge!

@tazabreu
Copy link

@tazmaniax it was, thanks for the explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants