在一次参与公司的技术讨论会上,一位同事在演示SpringBoot的JPA的操作时,发现SpringBoot的JPA的save操作时,发现会先有select再insert,然后老板说,我们在网关已经处理过select了,我们调用save肯定是想直接保存的,所以这个问题记下来,下面去解决下这个问题。虽然只是实习生,但是还是想知道这个问题的,如果就自己试了下,想知道里面的原因。
StudentRepository:
package com.hyl.springboot.Repository;
import com.hyl.springboot.Entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author HYL
* @Date 2019/10/31 下午7:56
* @Version 1.0
**/
/**
* 参数一:当前需要映射的实体
* 参数二:当前映射的实体中OID的类型
*/
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
Student:
package com.hyl.springboot.Entity;
import javax.persistence.*;
/**
* @Author HYL
* @Date 2019/10/31 下午7:52
* @Version 1.0
**/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
SpringTest:
package com.hyl.springdatajpa.test;
package com.hyl.springboot;
import com.hyl.springboot.Entity.Student;
import com.hyl.springboot.Repository.StudentRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringbootApplication.class)
public class SpringbootApplicationTests {
@Autowired
public StudentRepository studentRepository;
@Test
public void testSave() {
Student student = new Student();
student.setAge(2);
student.setName("242");
studentRepository.save(student);
}
}
我们通过改变我们我们testSaveStudent的方法来测试:
-
当传入不带自增主键时
@Test public void testSave() { Student student = new Student(); student.setAge(35); student.setName("上官云雀"); studentRepository.save(student); }
2.当传入带自增主键并且数据库不存在时
@Test
public void testSave() {
Student student = new Student();
student.setId(37);
student.setAge(35);
student.setName("上官云雀");
studentRepository.save(student);
}
3.当传入带自增主键并且数据库存在时(当前主键存在数据)
@Test
public void testSave() {
Student student = new Student();
student.setId(19);
student.setAge(34);
student.setName("上官云雀");
studentRepository.save(student);
}
总结:
源码分析:
@Transactional
@Override
public <S extends T> S save(S entity) {
//当当前实体为一个新的就把当前实体实例化并持久化
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
//将给定实体的状态合并到当前的持久性上下文
return em.merge(entity);
}
}
persist:
/**
* Make an instance managed and persistent.
* @param entity entity instance
* @throws EntityExistsException if the entity already exists.
* (If the entity already exists, the <code>EntityExistsException</code> may
* be thrown when the persist operation is invoked, or the
* <code>EntityExistsException</code> or another <code>PersistenceException</code> may be
* thrown at flush or commit time.)
* @throws IllegalArgumentException if the instance is not an
* entity
* @throws TransactionRequiredException if there is no transaction when
* invoked on a container-managed entity manager of that is of type
* <code>PersistenceContextType.TRANSACTION</code>
*/
public void persist(Object entity);
当前实体为一个新的就把当前实体实例化并持久化
merge:
/**
* Merge the state of the given entity into the
* current persistence context.
* @param entity entity instance
* @return the managed instance that the state was merged to
* @throws IllegalArgumentException if instance is not an
* entity or is a removed entity
* @throws TransactionRequiredException if there is no transaction when
* invoked on a container-managed entity manager of that is of type
* <code>PersistenceContextType.TRANSACTION</code>
*/
public <T> T merge(T entity);
persist会把传进去的实体放到持久化上下文中,此时如果持久化上下文中有了这个实体,就会抛出javax.persistence.EntityExistsException,没有的话事务提交的时候把那个对象加进数据库中。
persist是保存,跟save方法一样,更接近持久化的含义;而merge是合并的意思,就是当保存的实体,根据主键id划分,如果已存在,那么就是更新操作,如果不存在,就是新增操作。
文章为ArvinHan原创,如果文章有错的地方欢迎指正,大家互相交流。