欧美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)文章

  • 使用lombok@Data啟動項目報錯問題及解決

    使用lombok@Data啟動項目報錯問題及解決

    在使用Lombok時,可能會遇到實體類中的@Data注解不生效,導(dǎo)致get方法找不到的問題,解決這一問題通常需要三個步驟:首先,檢查項目設(shè)置中編譯規(guī)則是否勾選;其次,確認(rèn)IDE中是否安裝了Lombok插件
    2024-10-10
  • Java 中解決Unsupported major.minor version 51.0的問題

    Java 中解決Unsupported major.minor version 51.0的問題

    本文主要介紹解決Unsupported major.minor version 51.0的問題, 這里給大家整理了詳細資料,有需要的小伙伴可以參考下
    2016-08-08
  • SpringAOP中基于注解實現(xiàn)通用日志打印方法詳解

    SpringAOP中基于注解實現(xiàn)通用日志打印方法詳解

    這篇文章主要介紹了SpringAOP中基于注解實現(xiàn)通用日志打印方法詳解,在日常開發(fā)中,項目里日志是必不可少的,一般有業(yè)務(wù)日志,數(shù)據(jù)庫日志,異常日志等,主要用于幫助程序猿后期排查一些生產(chǎn)中的bug,需要的朋友可以參考下
    2023-12-12
  • 關(guān)于Kill指令停掉Java程序的問題

    關(guān)于Kill指令停掉Java程序的問題

    這篇文章主要介紹了Kill指令停掉Java程序的思考,主要探究kill指令和java的關(guān)閉鉤子的問題,需要的朋友可以參考下
    2021-10-10
  • Java設(shè)計模式之原型模式(Prototype模式)介紹

    Java設(shè)計模式之原型模式(Prototype模式)介紹

    這篇文章主要介紹了Java設(shè)計模式之原型模式(Prototype模式)介紹,本文講解了如何使用原型模式并給出了代碼實例,需要的朋友可以參考下
    2015-03-03
  • java開發(fā)只要tomcat設(shè)計模式用的好下班就能早

    java開發(fā)只要tomcat設(shè)計模式用的好下班就能早

    這篇文章主要為大家介紹了java開發(fā)只要tomcat設(shè)計模式的示例詳解,<BR>只要設(shè)計模式用的好下班就能早,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式

    這篇文章主要介紹了sprintboot使用spring-security包,緩存內(nèi)存與redis共存方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 教你如何寫springboot接口?

    教你如何寫springboot接口?

    這篇文章主要介紹了教你如何寫springboot接口,Spring?Boot是由Pivotal團隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。該框架使用了特定的方式來進行配置,從而使開發(fā)人員不再需要定義樣板化的配置,需要的朋友可以參考y一下
    2022-01-01
  • maven混淆打包的實現(xiàn)步驟

    maven混淆打包的實現(xiàn)步驟

    本文主要介紹了maven混淆打包的實現(xiàn)步驟,包含了Maven項目混淆、瘦身、打包exe這幾個方面,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • java使用mysql預(yù)編譯語句查詢優(yōu)勢及示例詳解

    java使用mysql預(yù)編譯語句查詢優(yōu)勢及示例詳解

    這篇文章主要為大家介紹了java使用mysql預(yù)編譯語句的優(yōu)勢特點及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06

最新評論