6

Background

I'm writing a project using Spring MVC (Framework v4.0.6.RELEASE, JPA v1.6.2.RELEASE) and Hibernate (Core v4.3.6.FINAL, JPA API v2.1). In my project, there are entities called 'Project'. Each of these projects have their unique, auto-generated IDs as primary keys. This ID is generated by the following code:

@Id
@Column(name = "project_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long projectId;

This code works as expected and automatically creates unique IDs.

Problem

Each of these projects are supposed to have a random, unique1 'secret' String, just like those assigned by API providers like Facebook, Twitter, etc. So, to achieve this, I tried using the following code, as per the Hibernate docs:

@Column(name = "project_secret", nullable = false, unique = true)
@GenericGenerator(name = "uuid-gen", strategy = "uuid")
@GeneratedValue(generator = "uuid-gen")
private String projectSecret;

However, whenever I try to create a new project entity, I'm greeted by a org.springframework.dao.DataIntegrityViolationException with root cause:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
Column 'project_secret' cannot be null

This should be auto-generated by Hibernate on creation, must be random and unique1. A 128-bit UUID is enough for me (32 characters w/out dashes) and I read that Hibernate has a UUID generator, so that's what I was aiming to use.

Further Info

After searching for hours, I'm no closer to solving it the way I want to do it. I found one possible solution, which is to include:

@PrePersist
private void generateSecret(){
    this.setProjectSecret(UUID.randomUUID().toString());
}

in the Project entity class. When this method is inserted (and @GenericGenerator & @GeneratedValue tags removed), the project secret is correctly generated and inserted; system works as expected; no exceptions are thrown. However, (I believe) this can't ensure uniqueness2 and just causes an exception when a duplicate secret is inserted. I want to ensure uniqueness and preferably want to solve this with built-in Hibernate generators.

(Notes)

  1. I actually am not sure if uniqueness should be enforced. I suppose having every secret unique can (theoretically) create an additional layer of security, which takes me to:
  2. I realise that the probability of UUID collision is very very low, so UUID generation ensures that uniqueness in a probabilistic sense but can (or should) I be really sure of it?
aemreunal
  • 85
  • 1
  • 1
  • 7
  • UUID duplication is extremely rare.. Read this http://stackoverflow.com/questions/1155008/how-unique-is-uuid – Pramod S. Nikam Aug 01 '14 at 14:23
  • 1
    @Orion Thank you for your time. That was one of the links I came by when I was questioning my 'uniqueness' requirement at the DB level, which I realise is debatable. But, as I stated, although I realise the probability of UUID collision is extremely rare, I want to **ensure** uniqueness. In the future, I may have a similar requirement with something other than UUIDs and I want to learn the correct way of doing this. – aemreunal Aug 01 '14 at 14:31

1 Answers1

4

I had an issue like this before and I realised after a while that it was my database table that was causing the issue. This might be the same problem you are having...

For your project_id ensure you use the following when you are creating that column in the database

GENERATED ALWAYS AS IDENTITY

I hope this is the same issue and that this will be of help to you. Also would recommend using uuid2 as your strategy.

see here... http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e5294

Edit

After realising that project_secret is not the @id field then the answer is that hibernate does not support generated values on any column except for the @id field. See here for more details : Hibernate JPA Sequence (non-Id)

Community
  • 1
  • 1
dectarin
  • 986
  • 5
  • 15
  • I don't really want to mess around with SQL, since I'm using Hibernate to not touch SQL. However, if I wanted to have that in my DDL, how can I insert it programatically? Also, to clarify, I don't have a problem with primary key/ID generation, so isn't generating 'AS IDENTITY' not applicable to my problem? – aemreunal Aug 01 '14 at 14:45
  • what type of database are you using? is it in-memory or is it persisted? – dectarin Aug 01 '14 at 14:47
  • sorry, i just noticed that the project_secret is not the @id field so i updated my answer with the real cause of your troubles :-/ – dectarin Aug 01 '14 at 15:22
  • That answered my question. Thank you very much. I'll be using the `@PrePersist` method; it's the closest to what I wanted. – aemreunal Aug 02 '14 at 12:16