简体   繁体   中英

Hibernate @GeneratedValue Sequence in multi threading

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();
        });
    }
}

The persistence provider is free to generate the ID whenever it wants to, as long as it respects the specifications (ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM