SpringDataJPA 高效批量操作

  • 一、背景:
  • 二、BatchService.java
  • 三、测试
  • 四、测试结果
  • 五、 实体类(附加)
  • 六、Repository.java(附加,个人觉得JPA很方便实用)
  • 七、application.yml(附加)

一、背景:

  • SpringDataJPA的API是没有高效批量操作的,它的saveAll底层是循环操作并且先读取数据库检查数据是否存在再去插入数据,性能效率很低。
  • 写过了好多增删改查的代码,功能也实现了很多,也是因为没有遇到大批量的MySQL数据库操作业务,就没有去找高效的数据库操作方法,之前的代码都是循环操作数据库。
  • 系统版本升级在今天差不多已经完结,迁移完数据库后,就顺便抽了时间找找怎么样能在SpringBoot整合的SpringDataJPA项目中高效的批量操作数据库,以便后期优化之前的代码,接下来言归正。
  • SpringDataJPA实战项目很好用,在第六标题有个人观点。

二、BatchService.java

  1. service实现层通过@PersistenceContext注解注入EntityManager接口。
  2. 批量写入调用persist方法(参数为实体对象),再调用flush刷新到数据库,后clear。
  3. 更新数据调用merge(参数为实体对象),同样调用flush刷新到数据库,后clear。
@Transactional
@Service
public class BatchService {@PersistenceContextprivate EntityManager entityManager;/*** 批量插入** @param list 实体类集合* @param <T>  表对应的实体类*/public <T> void batchInsert(List<T> list) {if (!ObjectUtils.isEmpty(list)){for (int i = 0; i < list.size(); i++) {entityManager.persist(list.get(i));if (i % 50 == 0) {entityManager.flush();entityManager.clear();}}entityManager.flush();entityManager.clear();}}/*** 批量更新** @param list 实体类集合* @param <T>  表对应的实体类*/public <T> void batchUpdate(List<T> list) {if (!ObjectUtils.isEmpty(list)){for (int i = 0; i < list.size(); i++) {entityManager.merge(list.get(i));if (i % 50 == 0) {entityManager.flush();entityManager.clear();}}entityManager.flush();entityManager.clear();}}
}

三、测试

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class DatabaseTest {@Value("${indexCode}")private String indexCode;@Resourceprivate StockRepository stockRepository;@Resourceprivate BatchService batchService;/*** 循环写入*/@Testpublic void forTest() {List<String> indexCodeArr = Arrays.asList(indexCode.split(","));Set<String> indexCodeSet = new HashSet<>(indexCodeArr);log.info("indexCodeSet:{}", JSONObject.toJSONString(indexCodeSet));log.info("indexCodeSe.size():{}", indexCodeSet.size());long timeIdStart = System.currentTimeMillis();String time = TimeUtil.FORMAT.get().format(timeIdStart);int record = 0;for (String indexCode : indexCodeSet) {record += stockRepository.updateIndexCalculated(indexCode, time);}log.info("record:{}", record);log.info("运行时间,time:{}秒", (System.currentTimeMillis() - timeIdStart) / 1000.0);}/*** 批量写入*/@Testpublic void batchTest() {List<String> indexCodeArr = Arrays.asList(indexCode.split(","));Set<String> indexCodeSet = new HashSet<>(indexCodeArr);log.info("indexCodeSet:{}", JSONObject.toJSONString(indexCodeSet));log.info("indexCodeSe.size():{}", indexCodeSet.size());long timeIdStart = System.currentTimeMillis();String time = TimeUtil.FORMAT.get().format(timeIdStart);List<IndexCalculated> list = new ArrayList<>();for (String indexCode : indexCodeSet) {IndexCalculated indexCalculated = new IndexCalculated();indexCalculated.setIndexCode(indexCode);indexCalculated.setUpdateTime(time);list.add(indexCalculated);}batchService.batchInsert(list);
//        batchService.batchUpdate(list);log.info("运行时间,time:{}秒", (System.currentTimeMillis() - timeIdStart) / 1000.0);}
}

四、测试结果

  1. 循环写入74条记录用时12.342秒。
  2. 批量写入74条记录用时2.139秒。
  3. 体验感受:循环写入方式操作几十条数据需要十多秒,而通过EntityManager批量操作则可以将时间减少到两秒,简直不要太爽!!

五、 实体类(附加)

@Table(name = "index_calculated")
@Entity
public class IndexCalculated implements Serializable {@Id@Column(name = "index_code")private String indexCode;@Column(name = "update_time")private String updateTime;public String getIndexCode() {return indexCode;}public void setIndexCode(String indexCode) {this.indexCode = indexCode;}public String getUpdateTime() {return updateTime;}public void setUpdateTime(String updateTime) {this.updateTime = updateTime;}
}

六、Repository.java(附加,个人觉得JPA很方便实用)

  1. nativeQuery属性设置为true,可以在value里写原生sql即数据库能直接运行的sql,避开JPA的API这样就很灵活,便于sql优化。
  2. 就第一点来说再加上SpringDataJPA与SpringBoot的方便整合,SpringDataJPA确实很方便好用,省去了Mybatis的xml配置。
@Repository
public interface StockRepository extends JpaRepository<IndexCalculated, String> {@Query(nativeQuery = true, value = "SELECT `stock_code` AS `stockCode`,`stock_name` AS `stockName`,`stock_display_name` AS `stockDisplayName` FROM `stock_security`")List<Map<String, Object>> stockIndexInfoOfStock();@Query(nativeQuery = true, value = "SELECT `index_code` AS `stockCode`,`index_name` AS `stockName`,`index_display_name` AS `stockDisplayName` FROM `index_info` WHERE `index_code` IN (SELECT `index_code` FROM `index_calculated`)")List<Map<String, Object>> stockIndexInfoOfIndex();@Query(nativeQuery = true, value = "SELECT `stock_code` FROM `sector_stock` WHERE `sector_code` IN ?1")List<Object> stockOfSector(String[] sectorCodeArr);@Query(nativeQuery = true, value = "SELECT `name` AS `sectorName`,`stock_code` AS `stockCode` FROM `industry_sector`,`sector_stock` WHERE industry_sector.`code`=sector_stock.`sector_code`")List<Map<String, Object>> industryOfStock();@Query(nativeQuery = true, value = "SELECT `index_code` AS `code`,`index_name` AS `name`,`index_display_name` AS `displayName` FROM `index_info` WHERE `index_code` IN (SELECT `index_code` FROM `index_calculated`)")List<Map<String, Object>> allIndexInfoOfCalculated();@Transactional@Modifying@Query(nativeQuery = true, value = "INSERT INTO `index_calculated`(`index_code`,`update_time`) VALUES (?1,?2)")int updateIndexCalculated(String indexCode, String updateTime);

七、application.yml(附加)

server:port: 9116
spring:#  main:#    web-application-type: nonedatasource:url: jdbc:mysql://###:3306/v1_stock_market_system?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2b8&autoReconnect=true&failOverReadOnly=falseusername: ###password: ###driver-class-name: com.mysql.jdbc.Driverhikari:read-only: falseconnection-timeout: 60000idle-timeout: 60000validation-timeout: 3000max-lifetime: 60000login-timeout: 5maximum-pool-size: 60minimum-idle: 10jpa:generate-ddl: falseshow-sql: falsehibernate:ddl-auto: nonedatabase: mysqlopen-in-view: trueredis:host: ###port: ###password: ###elasticsearch:jest:uris: http://###:9132,http://###:9132,http://###:9132,http://###:9132,http://###:9132indexCode: "399695.XSHE,399005.XSHE,399001.XSHE,000003.XSHG,000002.XSHG,000001.XSHG,399006.XSHE,000016.XSHG,000033.XSHG,000034.XSHG,000036.XSHG,000039.XSHG,000040.XSHG,000041.XSHG,000042.XSHG,000055.XSHG,000056.XSHG,000062.XSHG,000097.XSHG,000122.XSHG,000134.XSHG,000158.XSHG,000159.XSHG,000160.XSHG,000161.XSHG,000162.XSHG,000300.XSHG,000812.XSHG,000813.XSHG,000819.XSHG,000941.XSHG,000943.XSHG,000944.XSHG,000945.XSHG,000949.XSHG,399001.XSHE,399005.XSHE,399006.XSHE,399300.XSHE,399355.XSHE,399356.XSHE,399368.XSHE,399380.XSHE,399393.XSHE,399394.XSHE,399395.XSHE,399396.XSHE,399417.XSHE,399418.XSHE,399419.XSHE,399420.XSHE,399429.XSHE,399431.XSHE,399432.XSHE,399433.XSHE,399434.XSHE,399436.XSHE,399438.XSHE,399439.XSHE,399440.XSHE,399441.XSHE,399678.XSHE,399687.XSHE,399688.XSHE,399693.XSHE,399695.XSHE,399803.XSHE,399804.XSHE,399805.XSHE,399806.XSHE,399808.XSHE,399928.XSHE,399929.XSHE,399960.XSHE,399991.XSHE,399994.XSHE,399996.XSHE,399106.XSHE"

SpringDataJPA 高效批量操作相关推荐

  1. asp.net gridview删除 获取到第一行第一列的单元格内容_VBA中的常用单元格引用方式...

    VBA编程经常和"对象"打交道,其中最频繁的对象大概就是"单元格"了.(听说您还没有对象?那--我想你大概需要一份Excel,包邮988--) 今天我们就来聊一 ...

  2. IntelliJ Idea列操作高效解决批量操作(生成枚举类实例)

    列操作可以提高编码的效率,尤其在数据量多的时候. 下面我们举例: 通过以下的.json生成一个枚举类,这里我们实验列操作来高效实现. 100:"continue"102:" ...

  3. Python培训教程分享:“高效实用” 的Python工具库

    作为一名合格Python技术员,对于Python工具库的使用是少不了的,本期Python培训教程就为大家分享的是""高效实用" 的Python工具库",希望能够 ...

  4. 《深入理解ElasticSearch》——2.4 批量操作

    本节书摘来自华章计算机<深入理解ElasticSearch>一书中的第2章,第2.4节,作者:[美] 拉斐尔·酷奇(Rafa Ku) 马雷克·罗戈任斯基(Marek Rogoziński) ...

  5. boot jpa mysql postman spring_springboot使用spring-data-jpa操作MySQL数据库

    我们在上一篇搭建了一个简单的springboot应用,这一篇将介绍使用spring-data-jpa操作数据库. 新建一个MySQL数据库,这里数据库名为springboot,建立user_info数 ...

  6. Redis批量操作详解及性能分析

    通过mget批量执行指令可以节约网络连接和数据传输开销,在高并发场景下可以节约大量系统资源.本文中,我们更进一步,比较一下redis提供的几种批量执行指令的性能. 1. 为什么需要批量执行redis指 ...

  7. 如何优雅的实现DML批量操作

    如何优雅的实现DML批量操作(转载) 昨天处理了一个业务同学的数据需求,简单来说就是对一张大表做一下数据清理,数据量在8千万左右,需要保留近一个月的数据,大概是400万左右. 对于数据的删除处理,尤其 ...

  8. CLI or GUI --- 要高效还是要易用? (该文作者的功底真的很深厚啊)

     目录(?) [+] 这篇文章很棒 转载过来欣赏地址httpwwwcnitblogcomaddonearchive2008010838581html 要高效还是要易用谈CLI与GUI 前言 定义 ...

  9. onenote快捷键_高效飞快地使用onenote快捷键:快捷键功能架构解析

    默认快捷键有近200组,涉及到的功能如此之多,但真正频繁使用的,可能也就几十组.如何从这么多快捷键中选择出自己需要的呢?你需要一张功能架构参考图. 1 默认快捷键功能架构图 官方文档已对快捷键做了初步 ...

最新文章

  1. java方法声明无效_java 方法声明无效 需要返回类型
  2. 1的恢复出厂设置在哪里_无线路由器怎么恢复出厂设置
  3. [蓝桥杯][2016年第七届真题]压缩变换(主席树求区间不同数的个数)
  4. 2.oracle物理结构,oracle实验2oracle物理结构管理
  5. [转载]Zookeeper开源客户端框架Curator简介
  6. Android开发笔记(一百零五)社会化分享SDK
  7. java工厂模式_java工厂模式
  8. PowerBuilder开发简单计算器
  9. c语言1到100奇数和与偶数和,C语言实现1到100的和奇数与偶数和
  10. 【RK按键】按键切换
  11. sass-loader@13.2.0“ has unmet peer dependency “webpack@^5.0.0“
  12. 如何随时远程开机并控制电脑
  13. 熔断器Hystrix
  14. 生物信息中的Markov链
  15. oracle增加表空间文件
  16. 互联网文艺复兴者——互联网之父Vinton G. Cerf
  17. 【Java 解析全国地址】Java 利用正则表达式完美解析全国省市区地址
  18. STM32F207 USB复合设备
  19. java软件开发面试常见问题,java面试技巧和注意事项
  20. acdsee 看不到缩略图不能批量查看的解决方法!哈哈!

热门文章

  1. [KALI] 新装KALI自动化配置
  2. 蓝桥杯试题 算法提高 Monday-Saturday质因子
  3. Python读取本地html文件内容存csv
  4. 小型企业局域网搭建(一)
  5. nodejs优雅的使用es6语法
  6. 读书笔记-大颠狂(非同寻常的大众幻想与群众性癫狂)
  7. 蚂蚁集团三项技术方案入选“2021年信息技术应用创新典型解决方案”
  8. 集音频和视频播放功能于一身的简易播放器
  9. 数据结构与算法之hashmap散列表查找
  10. Virtual Box安装Ubuntu