JPA批量操作及性能比对

 

假设需要批量插入10000条实体数据至数据库。如下是各个操作方法及耗时环境Spring boot

1、JDBC(JdbcTemplate)

pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

Service

@Autowired
private JdbcTemplate jdbcTemplate;

public void jdbc(List<String> list){
int[] updatedCountArray=jdbcTemplate.batchUpdate("INSERT INTO customer (name) VALUES (?);", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
preparedStatement.setString(1,list.get(i));
}

@Override
public int getBatchSize() {
return list.size();
}
});
}

2、网上最常见的JPA----entityManager批量操作方法

Entity

package net.xjdsz.model;

import javax.persistence.*;

/**
* Created by dingshuo on 2017/6/23.
*/
@Entity
@Table(name = "customer", schema = "test", catalog = "")
public class CustomerEntity {
private int id;
private String name;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

@Basic
@Column(name = "name", nullable = true, length = 100)
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

CustomerEntity that = (CustomerEntity) o;

if (id != that.id) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;

return true;
}

@Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}

Service

private EntityManager em;

@PersistenceContext(name = "EntityManagerFactory")
public void SetEntityManager(EntityManager em) {
this.em = em;
}

@Transactional
public void saveBatch(List<CustomerEntity> list) {

for (int i = 0; i < 10000; i++) {

em.persist(list.get(i));
if (i % 1000 == 0) {
em.flush();
em.clear();
}
}
}

3、Jpa---Repository循环写入

Repository

package net.xjdsz.dao;

import net.xjdsz.model.CustomerEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
* Created by dingshuo on 2017/6/23.
*/
@Repository
public interface CustomerRepository extends JpaRepository<CustomerEntity,Integer> {

}

4、Jpa--Repository批量写入

Service

@Transactional
public void saveBatchJpa(List<CustomerEntity> list) {
repository.save(list);
}

实验代码:

扫描二维码关注公众号,回复: 9869581 查看本文章

用的是Spring boot,所以开了一个RestController去做实验

package net.xjdsz;

import net.xjdsz.dao.CustomerRepository;
import net.xjdsz.dao.TestService;
import net.xjdsz.model.CustomerEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
* Created by dingshuo on 2017/6/23.
*/
@RestController
public class TestController {
@Autowired
TestService service;//测试用的Service类

@Autowired
CustomerRepository repository; //实体Repository接口

@GetMapping(value = "/test")
public void test(){
List<String> list=new ArrayList<>(); //给jdbctemplate用的集合
List<CustomerEntity> customerEntityList=new ArrayList<>();//给jpa用的集合

for(int i=0;i<10000;i++){
list.add("学生"+i);
CustomerEntity customerEntity=new CustomerEntity();
customerEntity.setName("学生"+i);
customerEntityList.add(customerEntity);
}

//1.jdbc
long startTime=System.currentTimeMillis(); //获取开始时间
service.jdbc(list);
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("jdbc程序运行时间: "+(endTime-startTime)+"ms");

//2.jpa-em
long startTime1=System.currentTimeMillis(); //获取开始时间
service.saveBatch(customerEntityList);
long endTime1=System.currentTimeMillis(); //获取结束时间
System.out.println("JPA-EM程序运行时间: "+(endTime1-startTime1)+"ms");


//3.jpa-循环
long startTime2=System.currentTimeMillis(); //获取开始时间
for(int i=0;i<customerEntityList.size();i++){
repository.save(customerEntityList.get(i));
}
long endTime2=System.currentTimeMillis(); //获取结束时间
System.out.println("JPA-循环程序运行时间: "+(endTime2-startTime2)+"ms");



//4.jpa-集合
long startTime3=System.currentTimeMillis(); //获取开始时间
repository.save(customerEntityList);
long endTime3=System.currentTimeMillis(); //获取结束时间
System.out.println("JPA-集合程序运行时间: "+(endTime3-startTime3)+"ms");

}
}

实验结果

  1. jdbc程序运行时间: 878ms
  2. JPA-EM程序运行时间: 2018ms
  3. JPA-循环程序运行时间: 21915ms
  4. JPA-集合程序运行时间: 2373ms

结论就是如果追求极致的性能(批量操作速度),优选JDBC。EM和JPA直接操作集合没有太大的性能区别,这对于新接触Spring JPA(比如我)的人来说,不比纠结有时候没法注入EM,直接使用JPA操作集合即可。

JPA的循环造作相当于对单条insert重复了10000遍,自然最慢,也不推荐了。

如下是JPA操作集合的代码,可以看出起始内部也是用的em,所以可以放心大胆的用了。

@Transactional
public <S extends T> List<S> save(Iterable<S> entities) {

List<S> result = new ArrayList<S>();

if (entities == null) {
return result;
}

for (S entity : entities) {
result.add(save(entity));
}

return result;
}


/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
*/
@Transactional
public <S extends T> S save(S entity) {

if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
发布了48 篇原创文章 · 获赞 26 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_38316721/article/details/103290838
今日推荐