easyexcel调用公共导出方法导出数据
easyexcel备忘
@Slf4j
public class ConditionDownloadUtil {//扫描在xboot 包下所有IService 接口的子类, 每次启动服务后, 重新扫描public final static Class[] classesExtendsIService = ClassUtil.scanPackageBySuper("cn.exrick.xboot", IService.class).toArray(new Class[1]);public static <T, E> void nonMultiQueryDownload(Class<T> clazz,QueryWrapper<T> queryWrapper,String excelName,Class<E> excelClazz,HttpServletResponse response) {if (ObjectUtils.isNotEmpty(clazz)) {//1. 根据入参中的class 来获取对应的IService BeanIService<T> targetIService = getTargetIService(clazz);/** 2. 由于查询/排序字段在每个模块中不同, 所以需要让调用方提供, 不再统一提供* 调用IService 的list() 方法获取查询符合条件的数据*/List<T> list = targetIService.list(queryWrapper);if (list == null || list.size() == 0) {throw ExceptionUtil.wrapRuntime("数据为空, 无法下载excel!");}//3. 将实体类List 转换为Excel 类ListList<E> excelList = list.stream().map(x -> BeanUtil.toBean(x, excelClazz, CopyOptions.create().setIgnoreError(true))).collect(Collectors.toList());//4. 调用EasyExcel 通用方法输出ExcelafterMultiQueryDownload(excelName, excelList, excelClazz, new CustomMergeStrategy(excelClazz, excelList.size()), response);} else {throw ExceptionUtil.wrapRuntime("实体类不能为空!");}}public static <E> void afterMultiQueryDownload(String excelName,List<E> excelList,Class<E> excelClass,WriteHandler writeHandler,HttpServletResponse response) {//1. 判断需要输入的Excel List 是否为空, 如果不为空, 则输入, 否则, 抛出异常if (CollectionUtil.isNotEmpty(excelList)) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + URLUtil.encode(excelName, StandardCharsets.UTF_8) + ".xlsx");//2. 输入Exceltry {ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel.write(response.getOutputStream()).excelType(ExcelTypeEnum.XLSX).head(excelClass).sheet();if (ObjectUtil.isNotEmpty(writeHandler)) {excelWriterSheetBuilder.registerWriteHandler(writeHandler);}//3. 清除Convertor 中的线程变量DictConverter.removeThreadLocal();excelWriterSheetBuilder.doWrite(excelList);} catch (Exception e) {StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw);e.printStackTrace(pw);log.error(sw.toString());if (e.getCause() instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) e.getCause();String cellMsg = "";CellData cellData = excelDataConvertException.getCellData();//这里有一个celldatatype的枚举值,用来判断CellData的数据类型CellDataTypeEnum type = cellData.getType();if (type.equals(CellDataTypeEnum.NUMBER)) {cellMsg = cellData.getNumberValue().toString();} else if (type.equals(CellDataTypeEnum.STRING)) {cellMsg = cellData.getStringValue();} else if (type.equals(CellDataTypeEnum.BOOLEAN)) {cellMsg = cellData.getBooleanValue().toString();}String errorMsg = String.format("excel表格:第%s行,第%s列,数据值为:%s,该数据值不符合要求,请检验后重新导入!<span style=\"color:red\">请检查其他的记录是否有同类型的错误!</span>", excelDataConvertException.getRowIndex() + 1, excelDataConvertException.getColumnIndex(), cellMsg);log.error(errorMsg);}}} else {throw ExceptionUtil.wrapRuntime("数据为空, 无法下载excel!");}}public <T, E> void dynamicHeadDownload(List<List<String>> headList,String excelName,List data,HttpServletResponse response) {//1. 判断Head List 是否为空, 如果不为空, 则输入, 否则, 抛出异常if (ObjectUtil.isNotEmpty(headList)) {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + excelName + ".xlsx");//2. 输入Exceltry {EasyExcel.write(response.getOutputStream()).head(headList).sheet().doWrite(data);} catch (Exception e) {StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw);e.printStackTrace(pw);log.error(sw.toString());if (e.getCause() instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) e.getCause();String cellMsg = "";CellData cellData = excelDataConvertException.getCellData();//这里有一个celldatatype的枚举值,用来判断CellData的数据类型CellDataTypeEnum type = cellData.getType();if (type.equals(CellDataTypeEnum.NUMBER)) {cellMsg = cellData.getNumberValue().toString();} else if (type.equals(CellDataTypeEnum.STRING)) {cellMsg = cellData.getStringValue();} else if (type.equals(CellDataTypeEnum.BOOLEAN)) {cellMsg = cellData.getBooleanValue().toString();}String errorMsg = String.format("excel表格:第%s行,第%s列,数据值为:%s,该数据值不符合要求,请检验后重新导入!<span style=\"color:red\">请检查其他的记录是否有同类型的错误!</span>", excelDataConvertException.getRowIndex() + 1, excelDataConvertException.getColumnIndex(), cellMsg);log.error(errorMsg);}}} else {throw new RuntimeException("数据为空, 无法下载excel!");}}/*** 添加表头* @param head* @param headers*/public static void addHead(String head, List<List<String>> headers) {ArrayList<String> list = new ArrayList<>(1);list.add(head);headers.add(list);}/*@SneakyThrowspublic void tablesDownload(ReportDownloadModel reportDownloadModel, HttpServletResponse response) {String excelName = URLEncoder.encode(reportDownloadModel.getExcelName(), "utf-8");List<ReportTableModel> tableList = reportDownloadModel.getTables();response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + excelName + ".xlsx");ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(new CustomCellWriteHandler()).registerWriteHandler(new CustomCellWriteHeightConfig()).needHead(Boolean.TRUE).build();//1. 定义标题二维数组ArrayList<List<String>> titleHead = new ArrayList<>();//2. 定义最终输出的excel 二维数组ArrayList<List<Object>> finalData = new ArrayList<>();//3. 定义空行ArrayList<Object> emptyLine = new ArrayList<>();emptyLine.add("");try {for (int i = 0; i < tableList.size() * 2; i = i + 2) {ReportTableModel reportTableModel = tableList.get(i / 2);List<List<String>> heads = reportTableModel.getHeads();List<List<Object>> data = reportTableModel.getData();String title = reportTableModel.getTitle();//3. 定义表名行ArrayList<String> titleLine = new ArrayList<>();titleLine.add(title);titleHead.add(titleLine);for (int j = 0; j < heads.size() - 1; j++) {ArrayList<String> empty = new ArrayList<>();empty.add("");titleHead.add(empty);}WriteTable writeTableForTitle = EasyExcel.writerTable(i).needHead(Boolean.TRUE).head(titleHead).build();excelWriter.write(null, writeSheet, writeTableForTitle);//4. 在表数据后添加空行finalData.addAll(data);finalData.add(emptyLine);WriteTable writeTableForData = EasyExcel.writerTable(i + 1).needHead(Boolean.TRUE).head(heads).build();excelWriter.write(finalData, writeSheet, writeTableForData);titleHead.clear();finalData.clear();}} catch (Exception e) {throw new RuntimeException("导出Excel 失败, 原因:" + e.getMessage());} finally {if (excelWriter != null) {excelWriter.finish();}}}*//*** 根据入参的类, 查找IService 中第一个泛型类型为入参类型的IService Bean* @param referenceType* @return*/private static <T> IService<T> getTargetIService(Class<T> referenceType) {Class targetClass = Arrays.stream(classesExtendsIService).filter(classExtendsIService -> ClassUtil.getTypeArgument(classExtendsIService).equals(referenceType)).findFirst().orElseThrow(() -> ExceptionUtil.wrapRuntime("没有对应的类!"));return (IService<T>) SpringUtil.getBean(targetClass);}}
public class CustomMergeStrategy implements RowWriteHandler {/*** 主键下标*/private Integer pkIndex;/*** 需要合并的列的下标集合*/private List<Integer> needMergeColumnIndex = new ArrayList<>();/*** DTO数据类型*/private Class<?> elementType;private Integer total;public CustomMergeStrategy(Class<?> elementType, Integer total) {this.elementType = elementType;this.total = total;}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {// 如果是标题,则直接返回if (isHead) {return;}// 获取当前sheetSheet sheet = writeSheetHolder.getSheet();if (null == pkIndex) {this.lazyInit(writeSheetHolder);}// 判断是否需要和上一行进行合并// 不能和标题合并,只能数据行之间合并if (row.getRowNum() <= 1) {return;}// 获取上一行数据Row lastRow = sheet.getRow(row.getRowNum() - 1);// 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并if (!lastRow.getCell(pkIndex).getStringCellValue().equalsIgnoreCase(row.getCell(pkIndex).getStringCellValue())|| row.getRowNum() == total) {int maxRow = sheet.getMergedRegions().stream().max(Comparator.comparingInt(CellRangeAddressBase::getLastRow)).orElse(new CellRangeAddress(0, 0, 0, 0)).getLastRow();needMergeColumnIndex.forEach(needMerIndex -> {int rowStart = maxRow + 1;int rowEnd = row.getRowNum() == total ? row.getRowNum() : row.getRowNum() - 1;if (rowEnd > rowStart) {sheet.addMergedRegionUnsafe(new CellRangeAddress(rowStart,rowEnd,needMerIndex,needMerIndex));}});}}/*** 初始化主键下标和需要合并字段的下标*/private void lazyInit(WriteSheetHolder writeSheetHolder) {// 获取当前sheetSheet sheet = writeSheetHolder.getSheet();// 获取标题行Row titleRow = sheet.getRow(0);// 获取DTO的类型Class<?> eleType = this.elementType;// 获取DTO所有的属性Field[] fields = eleType.getDeclaredFields();// 遍历所有的字段,因为是基于DTO的字段来构建excel,所以字段数 >= excel的列数Arrays.stream(fields).forEach(field -> {// 获取@ExcelProperty注解,用于获取该字段对应在excel中的列的下标ExcelProperty easyExcelAnno = field.getAnnotation(ExcelProperty.class);// 为空,则表示该字段不需要导入到excel,直接处理下一个字段if (null == easyExcelAnno) {return;}// 获取自定义的注解,用于合并单元格CustomMerge customMerge = field.getAnnotation(CustomMerge.class);// 没有@CustomMerge注解的默认不合并if (null == customMerge) {return;}for (int index = 0; index < fields.length; index++) {Cell theCell = titleRow.getCell(index);// 当配置为不需要导出时,返回的为null,这里作一下判断,防止NPEif (null == theCell) {continue;}// 将字段和excel的表头匹配上if (easyExcelAnno.value()[0].equalsIgnoreCase(theCell.getStringCellValue())) {if (customMerge.isPk()) {pkIndex = index;}if (customMerge.needMerge()) {needMergeColumnIndex.add(index);}}}});// 没有指定主键,则异常if (null == this.pkIndex) {throw new IllegalStateException("使用@CustomMerge注解必须指定主键");}}}
@Data
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, verticalAlignment = VerticalAlignmentEnum.CENTER, wrapped = BooleanEnum.TRUE)
public class RiskAnnualExcel implements Serializable {@ExcelProperty("风险编号")@CustomMerge(needMerge = true, isPk = true)@ColumnWidth(15)@NotNullprivate String number;@ExcelProperty(value = "风险类别", converter = DictConverter.class)@DictType("risk-type")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String type;@ExcelProperty("风险名称")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String name;@ExcelProperty("风险描述")@CustomMerge(needMerge = true)@ColumnWidth(30)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT, verticalAlignment = VerticalAlignmentEnum.CENTER, wrapped = BooleanEnum.TRUE)@NotNullprivate String description;@ExcelProperty("可能造成的后果")@CustomMerge(needMerge = true)@ColumnWidth(15)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT, verticalAlignment = VerticalAlignmentEnum.CENTER, wrapped = BooleanEnum.TRUE)@NotNullprivate String consequence;@ExcelProperty(value = "风险等级", converter = DictConverter.class)@DictType("risk-level-for-company")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String level;@ExcelProperty(value = "风险性质", converter = DictConverter.class)@DictType("risk-character")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String character;@ExcelProperty(value = "风险主要防控措施")@ColumnWidth(80)@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT, verticalAlignment = VerticalAlignmentEnum.CENTER, wrapped = BooleanEnum.TRUE)@NotNullprivate String precaution;@ExcelProperty(value = "措施等级", converter = DictConverter.class)@DictType("risk-precaution-level")@ColumnWidth(15)@NotNullprivate String precautionLevel;@ExcelProperty("风险认领领导")@ColumnWidth(20)private String leaders;@ExcelProperty("管控部门")@ColumnWidth(20)@NotNullprivate String deptsResponsible;@ExcelProperty("风险涉及单位")@ColumnWidth(20)private String deptsInvolved;@ExcelProperty("措施类型")@ColumnWidth(15)@NotNullprivate String typeMeasures;@ExcelProperty("措施类别")@ColumnWidth(15)@NotNullprivate String categoryMeasures;@ExcelProperty("预警条件")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String warningConditions;@ExcelProperty("风险点")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String riskPoints;@ExcelProperty("应急措施")@CustomMerge(needMerge = true)@ColumnWidth(15)@NotNullprivate String emergencyMeasure;@ExcelProperty("备注")@CustomMerge(needMerge = true)@ColumnWidth(15)private String remark;}
调用公共导出方法导出数据
ConditionDownloadUtil.
afterMultiQueryDownload(riskBankAnnual.getName(),excelList, RiskAnnualExcel.class, new CustomMergeStrategy(RiskAnnualExcel.class,excelList.size()), httpServletResponse);
相关文章:
easyexcel调用公共导出方法导出数据
easyexcel备忘 Slf4j public class ConditionDownloadUtil {//扫描在xboot 包下所有IService 接口的子类, 每次启动服务后, 重新扫描public final static Class[] classesExtendsIService ClassUtil.scanPackageBySuper("cn.exrick.xboot", IService.class).toArra…...

C语言插入排序算法及代码
一、原理 在待排序的数组里,从数组的第二个数字开始,通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 二、代码部分 #include<stdio.h> #include<stdlib.h> int ma…...

2023年中国法拍房用户画像和数据分析
法拍房主要平台 法拍房主要平台有3家,分别是阿里、京东和北交互联平台。目前官方认定纳入网络司法拍卖的平台共有7家,其中阿里资产司法拍卖平台的挂拍量最大。 阿里法拍房 阿里法拍房数据显示2017年,全国法拍房9000套;2018年&a…...
Android 清除临时文件,清空缓存
python 代码: import os import shutil import tracebackdef delete_folder(path):if os.path.exists(path):print(f"删除文件夹: {path}")shutil.rmtree(path)print("删除完成")def delete_file(path):if os.path.exists(path):print(f"删…...

Guava限流神器:RateLimiter使用指南
1. 引言 可能有些小伙伴听到“限流”这个词就觉得头大,感觉像是一个既复杂又枯燥的话题。别急,小黑今天就要用轻松易懂的方式,带咱们一探RateLimiter的究竟。 想象一下,当你去超市排队结账时,如果收银台开得越多&…...

【六大排序详解】开篇 :插入排序 与 希尔排序
插入排序 与 希尔排序 六大排序之二 插入排序 与 希尔排序1 排序1.1排序的概念 2 插入排序2.1 插入排序原理2.2 排序步骤2.3 代码实现 3 希尔排序3.1 希尔排序原理3.2 排序步骤3.3 代码实现 4 时间复杂度分析 Thanks♪(・ω・)ノ下一篇文章见&am…...
凸优化问题求解
这里写目录标题 1. 线性规划基本定理2.单纯形法2.1 转轴运算 3. 内点法3.1 线性规划的内点法 1. 线性规划基本定理 首先我们指出,线性规划均可等价地化成如下标准形式 { min c T x , s . t A x b , x ⪰ 0 , \begin{align}\begin{cases}\min~c^Tx,\\\mathrm{s.…...

文件操作入门指南
目录 一、为什么使用文件 二、什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 三、文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 四、文件的顺序读写 编辑 🌻深入理解 “流”: 🍂文件的顺序读写函数介绍: …...

Axure之交互与情节与一些实例
目录 一.交互与情节简介 二.ERP登录页到主页的跳转 三.ERP的菜单跳转到各个页面的跳转 四.省市联动 五.手机下拉加载 今天就到这里了,希望帮到你哦!!! 一.交互与情节简介 "交互"通常指的是人与人、人与计算机或物体…...
【数据库设计和SQL基础语法】--连接与联接--多表查询与子查询基础(二)
一、子查询基础 1.1 子查询概述 子查询是指在一个查询语句内部嵌套另一个查询语句的过程。子查询可以嵌套在 SELECT、FROM、WHERE 或 HAVING 子句中,用于从数据库中检索数据或执行其他操作。子查询通常返回一个结果集,该结果集可以被包含它的主查询使用…...

Android studio中导入opencv库
具体opencv库的导入流程参考链接:Android Studio开发之路 (五)导入OpenCV以及报错解决 一、出现的错误:NullPointerException: Cannot invoke “java.io.File.toPath()” because “this.mySdkLocation” is null 解决办法&#…...
Linux(1)_基础知识
第一部分 一、Linux系统概述 创始人:芬兰大学大一的学生写的Linux内核,李纳斯托瓦兹。 Linux时unix的类系统; 特点:多用户 多线程的操作系统; 开源操作系统; 开源项目:操作系统,应用…...
网络相关面试题
简述 TCP 连接的过程(淘系) 参考答案: TCP 协议通过三次握手建立可靠的点对点连接,具体过程是: 首先服务器进入监听状态,然后即可处理连接 第一次握手:建立连接时,客户端发送 syn 包…...
Vue2面试题:说一下对跨域的理解?
http请求分为两大类:普通http请求(如百度请求)和ajax请求(跨域是出现在ajax请求) 同源策略:在浏览器发起ajax请求时,当前的网址和被请求的网址协议、域名、端口号必须完全一致,目的是…...

Axure中如何使用交互样式交互事件交互动作情形
🎬 艳艳耶✌️:个人主页 🔥 个人专栏 :《产品经理如何画泳道图&流程图》 ⛺️ 越努力 ,越幸运 目录 一、Axure中交互样式 1、什么是交互样式? 2、交互样式的作用? 3、Axure中如何…...
1112. 迷宫(DFS之连通性模型)
1112. 迷宫 - AcWing题库 一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n 的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。 同时当Extense处在某个格点时,他只…...

飞天使-k8s知识点1-kubernetes架构简述
文章目录 名词功能要点 k8s核心要素CNCF 云原生框架简介k8s组建介绍 名词 CI 持续集成, 自动化构建和测试:通过使用自动化构建工具和自动化测试套件,持续集成可以帮助开发人员自动构建和测试他们的代码。这样可以快速检测到潜在的问题,并及早…...
linux中deadline调度原理与代码注释
简介 deadline调度是比rt调度更高优先级的调度,它没有依赖于优先级的概念,而是给了每个实时任务一定的调度时间,这样的好处是:使多个实时任务场景的时间分配更合理,不让一些实时任务因为优先级低而饿死。deadline调度…...
jquery、vue、uni-app、小程序的页面传参方式
jQuery、Vue、Uni-app 和小程序(例如微信小程序)都有它们自己的页面传参方式。下面分别介绍这几种方式的页面传参方式: jQuery: 在jQuery中,页面传参通常是通过URL的查询参数来实现的。例如: <a href"page2…...

ModuleNotFoundError: No module named ‘openai.error‘
ModuleNotFoundError: No module named ‘openai.error’ result self.fn(*self.args, **self.kwargs) File “H:\chatGPTWeb\chatgpt-on-wechat\channel\chat_channel.py”, line 168, in _handle reply self._generate_reply(context) File “H:\chatGPTWeb\chatgpt-on-wec…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...