数据库大量数据导出导入的操作

news2024/9/28 23:36:01

基于上一篇文章,我想到如果在数据库之间拥有大量数据的表数据的导入导出,该如何快速完成表的导入导出工作呢?
思路一:使用db软件工具导出数据,然后向新数据库导入数据。我用的是dbserver22.3.4,不出意外的是,报了内存不足的异常。故这条路走不通
在这里插入图片描述
思路二:使用java程序按量读取表数据,写入txt文件存储,循环此过程,直至表数据全部写入txt文件,然后切换数据源url,使用java程序读取txt文件,最后使用原生jdbc向数据库中插入数据。说干就干!!!
1.按量读取表数据
使用 selext * from example 是不行的 别问我怎么知道的,要问就是试过,光这一条sql的读取时间就不止0.5h,果断放弃!!!
一条路不行,就换一条路!! 我想到的是换一条路,即按量读取数据,10w条数据读入在写入txt文件,循环此过程,直至读取写入完毕。
原生jdbc是最底层的,故效率是最高的。参考了大神博客和大神博客这两篇博客,写了以下代码



    @Autowired
    private ExampleController exampleController;

    @Autowired
    private SysMenuService sysMenuService;

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;


    @Test
    void context() throws SQLException{
//        List<Example> examples = exampleController.getList(null);
//        examples.size();
        Long start = System.currentTimeMillis();
        String sql = "select * from Example";
        Connection conn = DriverManager.getConnection(url,username,password);
        conn.setAutoCommit(false);
        PreparedStatement ps = conn.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY);
        ps.setFetchSize(100000);
        ps.setFetchDirection(ResultSet.FETCH_REVERSE);
        int totleCount = 0 ;
        ResultSet resultSet = ps.executeQuery();
        while(resultSet.next()){
            totleCount ++;
        }
        resultSet.close();
        ps.close();
        conn.close();
        Long end = System.currentTimeMillis();
        log.info("耗时"+(end-start)+"ms");
        log.info("耗时"+(end-start)+"ms");
    }

结果如下:
在这里插入图片描述

读取1000w条数据,耗时18s。原生jdbc yyds!!!
接下来就是做写入操作。
继续思考,读出来的数据写入到文件,这个时间估计会很长,如果不写入,直接在程序中使用新的数据源插入新数据库,这个时间预计会比较短,说干就干!!

@Test
    void context() throws SQLException{
//        List<Example> examples = exampleController.getList(null);
//        examples.size();
        List<Example> exampleList = new ArrayList<>();
        Example example = null;
        Long start = System.currentTimeMillis();
        String sql = "select * from Example";

        // 数据源1
        String url = "jdbc:mysql://127.0.0.1:3306/springboot_base?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true";
        Connection conn = DriverManager.getConnection(url,username,password);
        conn.setAutoCommit(false);
        // 数据源2
        String urlNew = "jdbc:mysql://127.0.0.1:3306/springboottest?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true";
        Connection connNew = DriverManager.getConnection(urlNew,username,password);
        // 注意一定要指明数据库   我这是本地数据库
        String sqlNew = "insert into springboottest.example (id,name,status,money,num,create_time) values (?,?,?,?,?,?)";
        PreparedStatement psNew = connNew.prepareStatement(sqlNew);
        connNew.setAutoCommit(false);

        // 数据源1的查询操作
        PreparedStatement ps = conn.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY);
        ps.setFetchSize(100000);
        ps.setFetchDirection(ResultSet.FETCH_REVERSE);
        int totleCount = 0 ;
        ResultSet rs = ps.executeQuery();
        Boolean isEnd = false;
        while(rs.next()){
            totleCount ++;
            example = new Example();
            example.setId(rs.getLong("id"));
            example.setName(rs.getString("name"));
            example.setStatus(rs.getString("status"));
            if (rs.getObject("money")!=null){
                example.setMoney(rs.getBigDecimal("money"));
            }
            if (rs.getObject("num")!=null){
                example.setNum(BigInteger.valueOf(rs.getLong("num")));
            }
            example.setCreateTime(rs.getTimestamp("create_time"));
            exampleList.add(example);
            if (totleCount % 100000 == 0){
                // 修改数据源
                if (totleCount == 10100000){
                    isEnd = true;
                }
                insertBatch(exampleList,isEnd,connNew,psNew);
                exampleList.clear();
                if (isEnd){
                    break;
                }
            }
        }
        rs.close();
        ps.close();
        psNew.close();
        conn.close();
        Long end = System.currentTimeMillis();
        log.info("耗时"+(end-start)+"ms");
    }
    /**
     * 向数据库中插入数据
     * @throws SQLException
     */
    void insertBatch(List<Example> exampleList,Boolean isEnd,Connection conn,PreparedStatement ps) throws SQLException {
        for (Example e:exampleList){
            ps.setLong(1,e.getId());
            ps.setString(2,e.getName());
            ps.setString(3,e.getStatus());
            if (e.getMoney() != null){
                ps.setObject(4,e.getMoney());
            }else {
                // ps设置money为空  第二个参数为数据库字段类型
                ps.setNull(4, Types.DECIMAL);
            }
            if (e.getNum() != null){
                ps.setObject(5,e.getNum());
            }else {
                ps.setNull(5, Types.BIGINT);
            }
            ps.setObject(6,e.getCreateTime());
            ps.addBatch();
        }
        ps.executeBatch();
        conn.commit();
        ps.clearParameters();
        if (isEnd){
            conn.close();
        }
    }

结果如下,耗时966762ms,即16分钟左右
在这里插入图片描述

转移拥有1000w条数据的表到另外一个数据库,耗时16min
若使用文件作为媒介,则大概率会降低效率,因为写入1000w条数据到文件,然后再读取有1000w条数据的文件,会很耗时,这里就放弃使用文件作为媒介了。
说一说优化吧,在sql传参的时候判断一下设置的值是否为NULL,这样会提高效率!!thanks!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/366487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【读书笔记】《深入浅出数据分析》第二章 检验你的理论

文章目录一&#xff0c;相关分析方法1&#xff0c;相关系数二&#xff0c;相关性不等于因果关系三&#xff0c;证明因果关系&#xff0c;“控制变量法”?本章主要说明了两个问题&#xff1a; 1&#xff0c;相关性不等于因果关系 2&#xff0c;如何判断两种数据之间是相关性&am…

深圳/东莞/惠州师资比较强的CPDA数据分析认证

深圳/东莞/惠州师资比较强的CPDA数据分析认证培训机构 CPDA数据分析师认证是中国大数据领域有一定权威度的中高端人才认证&#xff0c;它不仅是中国较早大数据专业技术人才认证、更是中国大数据时代先行者&#xff0c;具有广泛的社会认知度和权威性。 无论是地方政府引进人才、…

Android 高性能列表:RecyclerView + DiffUtil

文章目录背景介绍一般刷新 notifyDataSetChanged()局部刷新实现调用代码准备工作创建 MyDiffUtilCallback 类继承 DiffUtil.Callback 抽象类MyAdpter 类代码实现步骤总结通过 log 证实 diffutil 的局部刷新diffutil 优化后台线程参考主线程参考diff 更新优化后写法相关参考背景…

Spring的一些知识点

什么是Spring&#xff1f; Spring是一种轻量级的开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 Spring的核心模块 Spring Core是基础模块&#xff0c;可以说Spring的其他功能都要依赖于该类库&#xff0c;主要提供IOC的依赖注入功能&#xff1b; Spri…

动手学深度学习v2—01数据操作+数据预处理

此次用到的虚拟环境&#xff1a;pytorchmwy项目名称&#xff1a;limuAI所需框架和工具&#xff1a;pytorch&#xff0c;pandas一、创建CSV文件所需工具&#xff1a;pandas在与项目同等目录下创建一个文件夹名为data&#xff0c;其中文件名称为house_tiny.csv。代码如下&#xf…

Java基础:拼图小游戏

涉及到的知识: 1.图形用户接口GUI(Graphical User Interface)用图形化的方式显示操作界面 两个体系: AWT包和Swing包 2.界面会用到JFrame类 3.界面中的菜单会用到JMenuBar, JMenu, JMenuItem 4.添加图片 在设置完JLabel的location之后还需要获得展示内容的窗体, 通过setLay…

吃鸡用什么蓝牙耳机效果好?手游吃鸡公认最好的几款蓝牙耳机

蓝牙耳机的作用很多&#xff0c;几乎每个人都需要一副很棒的耳机在通勤或锻炼途中使用&#xff0c;并且玩游戏也少不了它&#xff0c;手游近几年十分的流行&#xff0c;下面整理了几款性能不错的蓝牙耳机。 第一款&#xff1a;南卡小音舱蓝牙耳机 蓝牙版本&#xff1a;5.3 发…

【Linux】如何将ntfs硬盘挂载到home目录下并具有读写权限

步骤1. 查看当前挂载的硬盘及其挂载点2. 查看需要挂载到home下的磁盘类型信息3. 在home下新建一个空的文件夹作为该磁盘的新挂载点4. 以ntfs类型的硬盘为例&#xff0c;使用mount命令进行挂载5. 问题1&#xff1a;进程占用了磁盘6. 问题2&#xff1a;磁盘权限为只读的7. 永久挂…

[AI助力] 2022.2.23 考研英语学习 2010 英语二翻译

[AI助力] 2022.2.23 考研英语学习 2010 英语二翻译 文章目录[AI助力] 2022.2.23 考研英语学习 2010 英语二翻译2010年英语二翻译真题自己写的积累&#x1f9d0;看看AI的翻译&#xff0c;学习学习&#xff08;把自己当成阅卷老师来康康hhh&#x1f920;DeepL谷歌翻译ReadPaper里…

JavaUDP通信程序

2 UDP通信程序 2.1 UDP通信原理 UDP协议是一种不可靠的网络协议&#xff0c;它在通信的两端各建立一个Socket对象, 但是这两个Socket只是发送&#xff0c;接收数据的对象因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念 Java提供了DatagramSocket类作为基…

低代码选型,论协同开发的重要性

Git是一款用于分布式版本控制的免费开源软件: 它可以跟踪到所有文件集中任意的变更&#xff0c;通常用于在软件开发期间&#xff0c;协调配合程序员之间的代码程序开发工作。 Git 最初诞生的原因源于Linux 内核的开发&#xff0c;2005年Linus Torvalds 编写出了Git。其他内核开…

AI作画—中国画之山水画

山水画&#xff0c;简称“山水”&#xff0c;中国画的一种&#xff0c;描写山川自然景色为主体的绘画。山水画在我国绘画史中占有重要的地位。 山水画形成于魏晋南北朝时期&#xff0c;但尚未从人物画中完全分离。隋唐时始终独立&#xff0c;五代、北宋时趋于成熟&#xff0c;…

Solon2 之基础:四、应用启动过程与完整生命周期

串行的处理过程&#xff08;含六个事件扩展点 两个函数扩展点&#xff09;&#xff0c;代码直接、没有什么模式。易明 提醒&#xff1a; 启动过程完成后&#xff0c;项目才能正常运行&#xff08;启动过程中&#xff0c;不能把线程卡死了&#xff09;AppBeanLoadEndEvent 之前…

【C++】类和对象(完结篇)

文章目录1. 再谈构造函数1.1 初始化列表1.2 explicit关键字2. static 成员2.1 静态成员变量2.1 静态成员函数2.3 练习2.4 总结3. 匿名对象4. 友元4.1 友元函数4.2 友元类5. 内部类6. 拷贝对象时编译器的一些优化7. 再次理解类和对象这篇文章呢&#xff0c;我们来再来对类和对象…

TypeScript学习笔记(一)编译环境、数据类型、函数类型、联合类型

文章目录编译环境基本类型函数类型函数重载联合类型和函数重载编译环境 TypeScript最终会被编译成JavaScript来运行&#xff0c;所以我们需要搭建对应的环境。 首先我们要全局安装typescript # 安装命令 npm install typescript -g # 查看版本 tsc --version⭐️ 方式一&…

【2023-2-23】FastDeploy 安装教程

【2023-2-22】FastDeploy 安装编译教程 该测试 FastDeploy CPU版本。 1. fastDeploy库编译 1.1 官方预编译库下载 预编译库下载安装 1.2 自定义CPU版本库编译 官方编译FastDeploy教程 CMakeGUI VS 2019 IDE编译FastDeploy 本人编译教程 CMAKE_CONFIGURATION_TYPES 属性设…

(三十一)大白话MySQL如果事务执行到一半要回滚怎么办?再探undo log回滚日志原理

之前我们已经给大家深入讲解了在执行增删改操作时候的redo log的重做日志原理&#xff0c;其实说白了&#xff0c;就是你对buffer pool里的缓存页执行增删改操作的时候&#xff0c;必须要写对应的redo log记录下来你做了哪些修改 如下图所示&#xff1a; 这样万一要是你提交事…

渗透测试之DNS域名信息探测实验

渗透测试之DNS域名信息探测实验实验目的一、实验原理1.1 域名1.2 .域名的构成1.3 域名的基本类型1.4 域名级别二、实验环境2.1 操作机器三、实验步骤1. 使用sp查询域名信息2. 进行探测实验实验目的 掌握使用nslookup进行DNS域名信息探测的原理和方式了解子域名查询网站 一、实…

PCB封装孔小,元器件无法插入,如何解决?

DIP就是插件&#xff0c;采用这种封装方式的芯片有两排引脚&#xff0c;可以直接焊在有DIP结构的芯片插座上或焊在有相同焊孔数的焊位中。其特点是可以很方便地实现PCB板的穿孔焊接&#xff0c;和主板有很好的兼容性。但是由于其封装面积和厚度都比较大&#xff0c;而且引脚在插…

Allegro如何打开格点显示效果操作指导

Allegro如何打开格点显示效果操作指导 Allegro可以设置格点显示效果,以格点来判定走线等等是否都处于格点上,如下图 如何打开格点显示效果,具体操作如下 点击Setup点击Grids