If you explicitly specify the id in spring-data-jpa and do `` `save```, select it as shown in the log below and then insert it.
Sample newEntity = new Sample(1L, "name");
repository.save(newEntity);
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 the behavior of jpa to select whether the id has already been persisted and then insert it. However, in some batch processing etc., it may be clear that the id does not exist as a specification. In this case, select is just useless and I want to prevent it. Below is how to prevent this pre-select.
build.gradle
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
Add a property to check the internally issued SQL.
src/main/resources/application.properties
spring.jpa.show-sql=true
Entity class. `Persistable`
will be described later.
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.data.domain.Persistable;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Sample implements Persistable<Long> {
@Id
Long id;
String name;
@Override
public Long getId() {
return id;
}
@Override
public boolean isNew() {
return true;
}
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@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;
@EnableJpaRepositories
@SpringBootApplication
public class JpaSample implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(JpaSample.class, args);
}
@Autowired
SampleRepository repository;
@Transactional
@Override
public void run(String... args) throws Exception {
Sample newEntity = new Sample(1L, "name");
repository.save(newEntity);
}
}
When the above code is executed, it changes to the following SQL log.
Hibernate: insert into sample (name, id) values (?, ?)
The save
of spring-data-jpa basically passes through the following `` `SimpleJpaRepository # save```, and its implementation is as follows.
SimpleJpaRepository
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(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, I want to prevent pre-select, that is, let JPA recognize it as a new entity, so I am trying to return ``
isNew to `` `true
.
Recommended Posts