2

I have 2 main entities Dog and Cat both of them have different fields except of id and dataVersion,
the id fields are NOT being generated by hibernate nor the db.
the field dataVersion is generated using @GeneratedValue with the same db sequence .

The problem is like this i have 2 threads:

  1. Thread 1 Creates entity Dog persists it and then it sleeps for 30 seconds
  2. Thread 2 starts 10 seconds after thread 1, thread 2 persists entity Cat and commits it.
  3. Thread 1 commits after 30 seconds

What I expect the database to have is entity Dog with dataVersion 2 and entity Cat with dataVersion 1, but somehow entity Dog has dataVersion 1 and entity Cat has dataVersion 2 .

I have searched allot on the internet about @GeneratedValue and I found out that the value is generated when the transaction is flushed so I turned off auto flush. The flush happens only when the transaction is committed and still I didn't get the expected result.

I would like to know what is the causing for this problem.


@Entity
@Getter
@Setter
public class Dog {
    @Id
    private String id;

    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dataVersionGen")
    @SequenceGenerator(name = "dataVersionGen", sequenceName = "DATA_VER_SEQ")
    private Long dataVersion;
}

@Entity
@Getter
@Setter
public class Cat {
    @Id
    private String id;

    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dataVersionGen")
    @SequenceGenerator(name = "dataVersionGen", sequenceName = "DATA_VER_SEQ")
    private Long dataVersion;
}

This is the code that's evaluate when the start running

@Component
public class Example {
    private ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    @Autowired
    private DBAccessor accessor;

    @PostConstruct
    public void example() {
        threadPoolTaskExecutor.initialize();

        // Starts dog's thread
        threadPoolTaskExecutor.execute(() -> {
            Dog dog = new Dog();
            dog.setId(UUID.randomUUID().toString());

            accessor.persist(dog);

            sleep(30 * SECOND);

            accessor.commit();
        });

       // Starts dog's thread
        threadPoolTaskExecutor.execute(() -> {
            sleep(10 * SECOND);

            Cat cat = new Cat();
            cat.setId(UUID.randomUUID().toString());

            accessor.persist(cat);
            accessor.commit();
        });
    }
}
Daniel Taub
  • 5,133
  • 7
  • 42
  • 72
Tomer Gal
  • 66
  • 5
  • 1
    The persistence provider is free to generate the ID whenever it wants to, as long as it respects the specifications (i.e. as long as the entity ends up having a unique ID in the database). You shouldn't assume that the ID is generated at flush time, because that's not necessarily the case. And you shouldn't care whether the cat has a lower or higher ID than the dog: what matters is that the ID is unique. – JB Nizet Aug 08 '18 at 16:38
  • 1
    @JBNizet can you please post this as answer? I'm tired of reading open questions with the answer in the comment. – Simon Martinelli Aug 09 '18 at 09:29

1 Answers1

1

The persistence provider is free to generate the ID whenever it wants to, as long as it respects the specifications (i.e. as long as the entity ends up having a unique ID in the database).

You shouldn't assume that the ID is generated at flush time, because that's not necessarily the case.

And you shouldn't care whether the cat has a lower or higher ID than the dog: what matters is that the ID is unique.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 1
    First of all thank you for the answer :) for personal reasons it is important for my program to generate the value according to the order they were commited. if you have any idea how to make it happen i would love to hear :) – Tomer Gal Aug 09 '18 at 10:50