欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出

 更新時間:2024年03月20日 09:36:41   作者:避暑人  
這篇文章主要為大家詳細介紹了SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出功能的相關(guān)知識,文中的示例代碼講解詳細,需要的小伙伴可以參考下

不用Mybatis的原因就是因為在大量數(shù)據(jù)插入的時候jdbc性能比mybatis好

1. 首先分批讀取Excel中的數(shù)據(jù) 這一點EasyExcel有自己的解決方案

2.其次就是DB里插入,怎么去插入這20w條數(shù)據(jù) 當(dāng)然不能一條一條循環(huán),應(yīng)該批量插入20w條數(shù)據(jù)

3.使用JDBC+事務(wù)的批量操作將數(shù)據(jù)插入到數(shù)據(jù)庫

整個Demo連接,打開下載即可,包含數(shù)據(jù)庫表

為什么mybatis的foreach比JDBC的addBatch慢

ORM 框架開銷:MyBatis 的 foreach 操作涉及到將對象數(shù)據(jù)轉(zhuǎn)換為 SQL 語句的過程,在這個過程中需要進行對象到 SQL 的映射、動態(tài) SQL 的解析等操作,這些額外的操作會增加開銷。

數(shù)據(jù)庫連接管理:MyBatis 在執(zhí)行 foreach 操作時,會頻繁地獲取和釋放數(shù)據(jù)庫連接,而數(shù)據(jù)庫連接的獲取和釋放是一個相對耗時的操作,特別在百萬級數(shù)據(jù)的情況下,這種開銷可能會積累導(dǎo)致性能下降。

SQL 語句生成:MyBatis 的 foreach 操作在執(zhí)行過程中會生成大量的 SQL 語句,這可能會導(dǎo)致數(shù)據(jù)庫的緩存失效、重新編譯查詢計劃等,從而影響性能。

批量插入優(yōu)化:JDBC 的 addBatch 可以直接利用底層數(shù)據(jù)庫的批量插入功能,而 MyBatis 的 foreach 操作在某些數(shù)據(jù)庫上可能不能充分利用數(shù)據(jù)庫的批量插入優(yōu)化。

1.引入依賴

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.2</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.42</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.18</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2.Controller層

@Slf4j
@RestController
@RequestMapping("excel")
public class ExcelController {
 
    @Autowired
    private UserService userService;
 
    //導(dǎo)出
    @GetMapping("/exportExcel")
    public String exportExcel(HttpServletRequest request, HttpServletResponse response){
        String file="D:";
        long startTime = System.currentTimeMillis();
        log.debug("-------------開始插入-------------------");
        userService.exportInspectionPlan(request,response);
        return "ok";
    }
 
 
    //導(dǎo)入
    @PostMapping("/importExcel")
    public void importExcel(MultipartFile multipartFile) throws IOException {
        if (multipartFile.isEmpty()) {
            return;
        }
        // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關(guān)閉
        // 這里每次會讀取3000條數(shù)據(jù) 然后返回過來 直接調(diào)用使用數(shù)據(jù)就行
        EasyExcel.read(multipartFile.getInputStream(), ExportPlanInformationVo.class,
            new PageReadListener<ExportPlanInformationVo>(dataList -> {
                            for (ExportPlanInformationVo user : dataList) {
                                //將導(dǎo)入的數(shù)據(jù)用mybatisPlus一個個添加進數(shù)據(jù)庫
                                System.out.println(user);
                            }
        })).sheet("現(xiàn)場巡視計劃報表").doRead();
    }
    /**
     * 1. 首先分批讀取Excel中的數(shù)據(jù)
     * 這一點EasyExcel有自己的解決方案
     *
     * 2.其次就是DB里插入,怎么去插入這20w條數(shù)據(jù)
     * 當(dāng)然不能一條一條循環(huán),應(yīng)該批量插入20w條數(shù)據(jù)
     * 同樣不能選擇Mybatis的批量插入,因為效率低
     *
     * 3.使用JDBC+事務(wù)的批量操作將數(shù)據(jù)插入到數(shù)據(jù)庫
     * */
    //批量導(dǎo)入
    @PostMapping("/batchImportExcel")
    public void batchImportExcel(MultipartFile file) throws IOException {
        if (BeanUtil.isEmpty(file)){
            log.debug("傳入的文件不能為空!");
            return ;
        }
        if (!Objects.requireNonNull(file.getOriginalFilename()).endsWith("xls") && !file.getOriginalFilename().endsWith("xlsx")){
            log.debug("請上傳Excel文件!");
            return ;
        }
        CommonExportListenerDto commonExportListenerDto = new CommonExportListenerDto();
        EasyExcel.read(file.getInputStream(),commonExportListenerDto).doReadAll();
    }
}

3.Service層

@Service
@Slf4j
public class UserService {
//
    @Resource
    private IndMapper indMapper;
    //文件導(dǎo)出
    public void exportInspectionPlan(HttpServletRequest request, HttpServletResponse response) {
        //以上需要根據(jù)自己的業(yè)務(wù)去做數(shù)據(jù)處理   這里就不做展示
        try {
            //給文件命名
            String fileName = "ExcelTest";
            // 設(shè)置響應(yīng)頭
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            // 設(shè)置防止中文名亂碼
            fileName = URLEncoder.encode(fileName, "utf-8");
            // 文件下載方式(附件下載還是在當(dāng)前瀏覽器打開)
            response.setHeader("Content-disposition", "attachment;filename=" +
                    fileName + ".xlsx");
            //向excel表格寫入數(shù)據(jù)
            EasyExcel.write(response.getOutputStream(), ExportPlanInformationVo.class)
                    .sheet("下方導(dǎo)航")
                    .doWrite(getAll());
/*
            //下載到指定路徑
            String fileUrl = "D://ExcelTest.xlsx";
            //向excel表格寫入數(shù)據(jù)
            EasyExcel.write(fileUrl, ExportPlanInformationVo.class)
                    .sheet("下方導(dǎo)航")
                    .doWrite(getAll());
*/
        } catch (Exception e) {
            log.error("出現(xiàn)錯誤 {}", e);
        }
    }
 
    public List<ExportPlanInformationVo> getAll(){
        //根據(jù)業(yè)務(wù)邏輯獲取數(shù)據(jù)
//        List<ExportPlanInformationVo> all = indMapper.getAll();
        return  indMapper.getAll();
    }
 
}

4.Utils工具類

import java.sql.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
 
public class JDBCUtil {
 
    private static String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false";
    private static String username = "root";
    private static String password = "196713";
    private static String driverName = "com.mysql.jdbc.Driver";
 
    /**
     * 獲取連接對象
     *
     * @return 連接對象
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            // 1. 注冊驅(qū)動
            Class.forName(driverName);
            // 2. 獲取連接對象
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return conn;
    }
 
 
    /**
     * 釋放資源
     *
     * @param connection 連接對象
     * @param statement  預(yù)編譯執(zhí)行對象
     * @param resultSet  結(jié)果集
     */
    public static void releaseResources(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        // 釋放資源
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
 
    public static void insertBatch(List<Map<Object, Object>> dataList, String sql) {
        Connection conn = null;
        PreparedStatement pstm = null;
        try {
            conn = getConnection();
            //如果需要開啟事務(wù)此處需要將自動提交關(guān)閉
            // conn.setAutoCommit(false);
            //預(yù)編譯sql
            pstm = (PreparedStatement) conn.prepareStatement(sql);
            for (Map<Object, Object> map : dataList) {
                //此處類型判斷不完整后續(xù)可以借鑒jdk自行封裝攔截器
                for (int i = 1; i <= map.size(); i++) {
                    Object o = map.get(i-1);
                    if (BeanUtil.isEmpty(o)) {
                        pstm.setString(i, null);
                        continue;
                    }
                    if (o instanceof String) {
                        pstm.setString(i, o.toString());
                        continue;
                    }
                    if (o instanceof Integer) {
                        pstm.setInt(i, Integer.parseInt(o.toString()));
                        continue;
                    }
                    if (o instanceof LocalDateTime) {
                        pstm.setDate(i, new Date(System.currentTimeMillis()));
                        continue;
                    }
                    if (o instanceof Boolean) {
                        pstm.setBoolean(i, Boolean.parseBoolean(o.toString()));
                    }
                }
                //添加到同一個批處理中
                pstm.addBatch();
            }
            //執(zhí)行批處理
            pstm.executeBatch();
            //如果需要開啟事務(wù)此處需要手動提交事務(wù)
            //conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
 
}

5.自定義監(jiān)聽器

@Data
@Slf4j
public class CommonExportListenerDto extends AnalysisEventListener<Map<Object, Object>> {
 
    /**
     * 表頭數(shù)據(jù)(存儲所有的表頭數(shù)據(jù))
     */
    private List<Map<Integer, String>> headList = new ArrayList<>();
 
    /*
     * 數(shù)據(jù)體
     */
    private List<Map<Object, Object>> dataList = new ArrayList<>();
 
    /**
     * 存儲全部表頭數(shù)據(jù)
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        headList.add(headMap);
    }
 
    /**
     * 每一條數(shù)據(jù)解析都會來調(diào)用
     * @param data
     * @param context
     */
    @Override
    public void invoke(Map<Object, Object> data, AnalysisContext context) {
        dataList.add(data);
        if (dataList.size() >= 3) {
            saveData();
            // 存儲完成清理 list
            dataList = ListUtils.newArrayListWithExpectedSize(2000);
        }
    }
 
    /**
     * 所有數(shù)據(jù)解析完成之后的操作
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        saveData();
    }
 
    private void saveData() {
        log.info("{}條數(shù)據(jù),開始存儲數(shù)據(jù)庫!", dataList.size());
        //批量導(dǎo)入
        JDBCUtil.insertBatch(dataList,"INSERT INTO ind (a,b,c,d,e) VALUES(?,?,?,?,?);");
        log.info("存儲數(shù)據(jù)庫成功!");
    }
}

6.實體類

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@HeadRowHeight(value = 30) // 頭部行高
@ContentRowHeight(value = 25) // 內(nèi)容行高
@ColumnWidth(value = 20) // 列寬
@HeadFontStyle(fontName = "宋體", fontHeightInPoints = 11)
public class ExportPlanInformationVo  implements Serializable {
 
// 1. 如果不想某個字段在excel中出現(xiàn)  可以加  @ExcelIgnore注解
    @ExcelProperty(value = "a")
    private String a;
 
 
//    @Dict(code = "inspectionType", fieldName = "inspectionTypeName")
    @ExcelProperty(value = "b")
    private String b;
 
    @ExcelProperty(value = "c")
    private String c;
    @ExcelProperty(value = "d")
    private String d;
    @ExcelProperty(value = "c")
    private String e;
 
 
}

7.Mapper層

@Mapper
public interface IndMapper {
 
    @Select("select * from ind")
    List<ExportPlanInformationVo> getAll();
 
}

以上就是SpringBoot整合EasyExcel實現(xiàn)批量導(dǎo)入導(dǎo)出的詳細內(nèi)容,更多關(guān)于SpringBoot EasyExcel導(dǎo)入導(dǎo)出的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解決Maven 項目報錯 java.httpservlet和synchronized使用方法

    解決Maven 項目報錯 java.httpservlet和synchronized使用方法

    下面小編就為大家?guī)硪黄鉀QMaven 項目報錯 java.httpservlet和synchronized使用方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java正則提取中括號中的內(nèi)容操作示例

    Java正則提取中括號中的內(nèi)容操作示例

    這篇文章主要介紹了Java正則提取中括號中的內(nèi)容操作,涉及Java針對字符串的正則匹配、轉(zhuǎn)換、遍歷等相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • JavaFx 實現(xiàn)按鈕防抖功能

    JavaFx 實現(xiàn)按鈕防抖功能

    最近Sun公司推出了JavaFX框架,使用它可以利用JavaFX編程語言來開發(fā)富互聯(lián)網(wǎng)應(yīng)用程序(RIA),這篇文章主要介紹了JavaFx 實現(xiàn)按鈕防抖功能,需要的朋友可以參考下
    2022-01-01
  • Spring框架 XML配置事務(wù)控制的步驟操作

    Spring框架 XML配置事務(wù)控制的步驟操作

    這篇文章主要介紹了Spring框架 XML配置事務(wù)控制的步驟操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 一次 Java 內(nèi)存泄漏的排查解決過程詳解

    一次 Java 內(nèi)存泄漏的排查解決過程詳解

    這篇文章主要介紹了一次 Java 內(nèi)存泄漏的排查過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • SpringBoot整合HikariCP數(shù)據(jù)庫連接池方式

    SpringBoot整合HikariCP數(shù)據(jù)庫連接池方式

    這篇文章主要介紹了SpringBoot整合HikariCP數(shù)據(jù)庫連接池方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • IDEA?2022?中的Lombok?使用基礎(chǔ)教程

    IDEA?2022?中的Lombok?使用基礎(chǔ)教程

    ? Lombok是使用java編寫的一款開源類庫。其主作用是使用注解來代替一些具有格式固定,沒有過多技術(shù)含量的編碼工作,這篇文章主要介紹了IDEA?2022?中的Lombok?使用基礎(chǔ)教程,需要的朋友可以參考下
    2022-12-12
  • SpringCloud Zuul網(wǎng)關(guān)功能實現(xiàn)解析

    SpringCloud Zuul網(wǎng)關(guān)功能實現(xiàn)解析

    這篇文章主要介紹了SpringCloud Zuul網(wǎng)關(guān)功能實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 關(guān)于Java中的頂層類修飾問題

    關(guān)于Java中的頂層類修飾問題

    這篇文章主要介紹了關(guān)于Java中的頂層類修飾問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 詳解使用Spring Boot開發(fā)Restful程序

    詳解使用Spring Boot開發(fā)Restful程序

    本篇文章主要介紹了詳解使用Spring Boot開發(fā)Restful程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評論