[Java] Make select-insert of save of Spring Data JPA only insert

1 minute read


When id is explicitly specified in spring-data-jpa and ```save

is performed, select it as shown in the log below and then insert.

Sample newEntity = new Sample(1L, "name");
Hibernate: select sample0_.id as id1_0_0_, sample0_.name as name2_0_0_ from sample sample0_ where sample0_.id=?
Hibernate: insert into sample (name, id) values (?, ?)

It is jpa’s behavior to insert after selecting whether id has already been persisted. However, in some batch processing, it may be clear that the id does not exist as a specification. In this case, select is simply wasted and we want to prevent it. Below is how to prevent this pre-select.

Source code


plugins {
  id'org.springframework.boot' version '2.3.3.RELEASE'
  id'io.spring.dependency-management' version '1.0.10.RELEASE'
group ='com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
  compileOnly {
    extendsFrom annotationProcessor
repositories {
dependencies {
  testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group:'org.junit.vintage', module:'junit-vintage-engine'
test {

Add a property to check internally issued SQL.



Entity class. ```Persistable

is described later.

import javax.persistence.Entity;
import javax.persistence.Id;

import org.springframework.data.domain.Persistable;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

public class Sample implements Persistable<Long> {
Long id;

String name;

public Long getId() {
return id;

public boolean isNew() {
return true;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

public interface SampleRepository extends JpaRepository<Sample, Long> {

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.Transactional;

public class JpaSample implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(JpaSample.class, args);

SampleRepository repository;
It's a sequel.
public void run(String... args) throws Exception {
Sample newEntity = new Sample(1L, "name");


Execution log

When the above code is executed, the SQL log changes as below.

Hibernate: insert into sample (name, id) values (?, ?)


The save of spring-data-jpa basically passes the following ```SimpleJpaRepository#save

and its implementation is as follows.

#### **`SimpleJpaRepository`**

public <S extends T> S save(S entity) {

if (entityInformation.isNew(entity)) {
return entity;
} else {
return em.merge(entity);

By default, isNew is false, so it becomes em.merge, resulting in select-insert. This behavior can be changed by implementing Persistable in the entity class. This time, we want to prevent pre-selection, that is, to let JPA recognize as a new entity, so isNew returns ```true