SpringBoot实现JPA的save操作

  在一次参与公司的技术讨论会上,一位同事在演示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的方法来测试:

  1. 当传入不带自增主键时

    @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原创,如果文章有错的地方欢迎指正,大家互相交流。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值