4

We have 2 java web apps both are read/write and 3 standalone java read/write applications (one loads questions via email, one processes an xml feed, one sends email to subscribers) all use hibernate and share a common code base.

The problem we have recently come across is that questions loaded via email sometimes overwrite questions created in one of the web apps. Note, these are separate questions which should have separate id's. We originally thought this to be a caching issue. We've tried turning off the second level cache, but this doesn't make a difference.

<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.cache.use_second_level_cache">false</property>

Question:

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
@DocumentId
public Integer getId() {
    return this.id;
}

We're using MySQL btw.

CREATE TABLE  `question` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  ...
  PRIMARY KEY (`id`),
  ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8

We are not explicitly opening and closing sessions, but rather let hibernate manage them via Util.getSessionFactory().getCurrentSession().

We'd rather not setup a clustered 2nd level cache at this stage as this creates another layer of complexity and we're more than happy with the level of performance we get from the app as a whole.

So does implementing a open-session-in-view pattern in the web apps and manually managing the sessions in the standalone apps sound like it would fix this?

Or any other suggestions/ideas please?

Austen
  • 131
  • 8
  • How are the questions identified (also what is the primary key) are the mail and web updates to the same question? – mmmmmm May 12 '10 at 08:36
  • It sound like the primary key is generated by the apps instead of using a sequence which is handled by the database. – khmarbaise May 12 '10 at 08:38
  • Hi, just updated my question with more info for you. I thought that the IDENTITY strategy caused the id to be generated by MySQL? – Austen May 12 '10 at 08:50

2 Answers2

3

Since all the questions have ids, then I assume that all questions are fetched from your MySql database.

Assuming that you don't need to store the questions as transparent objects in memory, but that you select all the questions for each time you present them, I have one simple suggestion.

Replace the ID generator with a sequence in the database. (Eventually the ID as autonumber in MySql). Then the database instead of the applications guarantees that every question gets a unique id.

This solution is quite simple and reduces your complexity. And it only works if you persist all incoming questions from the different sources into your database and then select them from here.

If this solution gives you performance problems, you should investigate more about how your Hibernate id generator work. Hibernate provides several different generators for different scenarios.

Hope this help!

Espen
  • 10,545
  • 5
  • 33
  • 39
  • I've added our schema for questions. so are you suggesting that we remove the @GeneratedValue(strategy = IDENTITY) annotation? – Austen May 12 '10 at 09:37
  • Yes I do. If several applications inserts values into the same table, then an insert trigger on the table is the most bullet proof solution. This trigger should set the ids from a sequence. – Espen May 12 '10 at 09:47
  • If I remove the @GeneratedValue annotation I get: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): Are you suggesting that I manually figure out the id direct from the database and then assign manually to new questions? – Austen May 12 '10 at 10:22
  • 1
    It was my understanding that GenerationType.IDENTITY works correctly with MySQL auto increment. See: http://stackoverflow.com/questions/582526/hibernate-not-respecting-mysql-auto-increment-primary-key-field – Austen May 12 '10 at 10:24
  • You can set the id field to for example -1 in the constructor or as field's default value. Then you will quite easy see if your database trigger works or not. – Espen May 12 '10 at 11:25
0

Turns out this problem wasn't related to Hibernate at all.

One of the database tables on the staging server was filled with old data that should have been cleaned up. This initially gave the appearance of id's being overwritten, but further investigation proved otherwise!

Once we removed the dodgy data, all was well.

Austen
  • 131
  • 8