JPA批量操作及性能比对
2024-08-30 16:31:23
假设需要批量插入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);
}
实验代码:
用的是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");
}
}
实验结果
jdbc程序运行时间: 878ms
JPA-EM程序运行时间: 2018ms
JPA-循环程序运行时间: 21915ms
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);
}
}
最新文章
- CSS的未来
- PHP:函数赋参数默认初值
- Gps与地图坐标转换
- MsSql数据库存储过程加密解密
- cannot access the system temp folder
- 10. 求N分之一序列前N项和
- winform中利用反射实现泛型数据访问对象基类(3)
- ACM Sdut 2158 Hello World!(数学题,排序) (山东省ACM第一届省赛C题)
- sdk安装
- Gym 101606L - Lounge Lizards - [计算几何+LIS]
- 面向复杂应用,Node.js中的IoC容器 -- Rockerjs/core
- Python学习笔记 -- 第六章 文件操作
- Scout YYF I POJ - 3744(概率dp + 矩阵快速幂)
- Cgod省选的爆零日记
- 【Java】 剑指offer(27) 二叉树的镜像
- Kubernetes 部署 1.9.7 高可用版
- Git error: hint: Updates were rejected because the remote contains work that you do hint: not have locally
- solr 5.2.1 tomcat 7 配置过程笔记
- DDD实战成绩管理---需求分析
- 从零开始用 Flask 搭建一个网站(四)