The issue was with the following code snippet:
MyEntity a = new MyEntity();
a.setUid("foo" + System.currentTimeMillis());
a.setName("my entity");
entityService.save(a);
This was part of some object creation code I was using in a unit test, which ran successfully every time on my macbook but was failing on other's windows machines. When I found out the reason behind this, I was definitely surprised.
Believe it or not, it is more or less a known issue that the resolution of currentTimeMillis() on windows machines hovers around 10-15ms (linux and mac have a resolution of around 1ms). This was causing duplicate foreign key violations to occur.
So, as a general rule of thumb, it is a bad idea to rely on currentTimeMillis() to have a millisecond-resolution on windows, especially if you are using it to generate unique things like file names or db IDs. Looks like System.nanoTime() might tick faster.
Here are some links I found on StackOverflow about this:
- Sleep Less Than One Millisecond
- In JavaScript, is there a source for time with a consistent resolution in milliseconds?
- How does any application (chrome, flash, etc) get a time resolution better then the system time resolution?
On Windows, you'll more or less be limited to 10 ms resolution at best. Here's a bit from the Inside Windows NT High Resolution Timers
Windows NT bases all of its timer support off of one system clock interrupt, which by default runs at a 10 millisecond granularity. This is therefore the resolution of standard Windows timers.
In my experience, using System.currentTimeMillis method gives about 15-16 ms resolution on Windows. Getting better time than the operating system timer will probably require more exotic methods.
Here's the StackOverflow question which helped me solve this issue:
http://stackoverflow.com/questions/351565/system-currenttimemillis-vs-system-nanotime
At the end of the day, I decided it was simpler for my test to use a static synchronized counter variable rather than depending upon currentTimeMillis() for generating my UIDs. Another possible solution could be to use UUID.randomUUID().toString().