0

I am developing Spring Boot (2.1.7.RELEASE) +Data Jpa + Postgres example. In this example I am explicitly passing EMP_ID value=100 and next I am allowing data-jpa to automatically take next Id which is 101. I am not sure why its not working in that way??

Employee.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Entity
public class Employee extends BaseEntity{

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "EMP_ID", unique = true, nullable = false)
    private Integer empId;

    @Column(name = "EMP_NAME", unique = true, nullable = false)
    private String empName;

    @Column(name = "EMP_EMAIL", unique = true, nullable = false)
    private String empEmail;


    @Builder(builderMethodName="eBuilder")
    public Employee(Integer empId, String empName, String empEmail,
            Instant createdDate, Instant lastUpdateDate,String createUser, String lastUpdateUser) {
        super(createdDate, lastUpdateDate, createUser, lastUpdateUser);
        this.empId = empId;
        this.empName = empName;
        this.empEmail = empEmail;
    }
}

BaseEntity.java

@Data
@MappedSuperclass
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
    @CreatedDate
    @Column(name = "createdDate", nullable = false, updatable = false)
    private Instant createdDate;

    @Column(name = "lastUpdateDate", nullable = false)
    @LastModifiedDate
    private Instant lastUpdateDate;

    @Column(name = "createUser", nullable = false, length = 50)
    private String createUser;

    @Column(name = "lastUpdateUser", length = 50)
    private String lastUpdateUser;
}

MainApp.java

@SpringBootApplication
@EnableJpaAuditing
public class MyExampleApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(MyExampleApplication.class, args);
    }

    @Autowired
    private EmployeeRepository employeeRepository;

    @Override
    public void run(String... args) throws Exception {
        Employee e = Employee.eBuilder().empId(100).empName("Shrutika")
                .empEmail("shrutika@hotmail.com")
                .createUser("Shrutika")
                .lastUpdateUser("Shrutika")
                .build();

        employeeRepository.save(e);

        Employee e1 = Employee.eBuilder().empName("Shantaram")
                .empEmail("shantaram@hotmail.com")
                .createUser("Shantaram")
                .lastUpdateUser("Shantaram")
                .build();
        employeeRepository.save(e1);
    }
}

enter image description here

Even if I used below, still things doesn't works well

@Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_generator")
    @SequenceGenerator(name="emp_generator", sequenceName = "emp_seq", allocationSize=1)
    @Column(name = "EMP_ID", unique = true, nullable = false)
    private Integer empId;

Spring JIRA: https://jira.spring.io/browse/DATAJPA-1588

Jeff Cook
  • 5,050
  • 13
  • 65
  • 127
  • Possible duplicate of https://stackoverflow.com/questions/38537463/how-to-set-initial-value-for-id-generatedvalue-in-spring-jpa-for-mysql – asolanki Aug 12 '19 at 03:27
  • @asolanki - I am not convience with the above link, by following : https://vladmihalcea.com/why-you-should-never-use-the-table-identifier-generator-with-jpa-and-hibernate/. Could you please suggest proper guidance ? – Jeff Cook Aug 12 '19 at 05:25
  • @JeffCook a sequence generator consists in getting the next ID from a database sequence. Not in getting the next ID from the ID you last inserted yourself. – JB Nizet Aug 12 '19 at 06:53
  • @JBNizet - Right. Agree. I always wanted to save records by always doing max id +1. Is there any way of doing this with Spring Data JPA? – Jeff Cook Aug 12 '19 at 06:59
  • No. This would be impossible to do in a concurrent-safe way, and would be horribly slow. – JB Nizet Aug 12 '19 at 07:14
  • As a alternative, I must be saying `initialValue=101` if I already have 100 as a Max Id present in DB ? `@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="seq") @SequenceGenerator(name="seq", initialValue=99, allocationSize=1)` – Jeff Cook Aug 12 '19 at 07:19
  • One approach I have seen is to have a sequence for JPA generated Ids and use negative IDs for ids generated by some other process. Although this certainly qualifies as a bad hack in 98% of the cases. – Jens Schauder Aug 19 '19 at 06:45
  • @JensSchauder - I am not clear on this. Could you please show some code ? – Jeff Cook Aug 19 '19 at 07:24

3 Answers3

0

Ensure the type EMP_ID on the database: SERIAL or Integer. For using IDENTITY with postgres it has to be SERIAL (https://www.postgresql.org/docs/8.1/datatype.html#DATATYPE-SERIAL).

sudo
  • 632
  • 4
  • 13
0

I am explicitly passing EMP_ID value=100 and next I am allowing data-jpa to automatically take next Id which is 101. I am not sure why its not working in that way??

JB Nizet answered that in the comments:

a sequence generator consists in getting the next ID from a database sequence. Not in getting the next ID from the ID you last inserted yourself.

I always wanted to save records by always doing max id +1. Is there any way of doing this with Spring Data JPA

Again JB Nizet pointed out this is a terrible idea. It would require a lock on the or at least the index for every insert including the select to determine the next id.

So: DON'T DO THIS

If you still want to do it Vlad Mihalcea describes how to implement a custom id generator. This should allow you to implement your own generator. Of course this is Hibernate specific.

Community
  • 1
  • 1
Jens Schauder
  • 65,795
  • 24
  • 148
  • 294
0

This will work:

@GeneratedValue(strategy=GenerationType.SEQUENCE)
Prashant K
  • 690
  • 7
  • 7