SQL Server大批量数据插入

news2025/1/3 17:50:24

数据库连接及相关操作

public class DataBase {
    /**
     * 驱动
     */
    private static final String DRIVER = PropertiesUtil.getString("spring.datasource.driver-class-name");

    /**
     * 数据库地址
     */
    private static final String URL = PropertiesUtil.getString("spring.datasource.url");

    /**
     * 数据库用户名
     */
    private static final String NAME = PropertiesUtil.getString("spring.datasource.username");

    /**
     * 数据库密码
     */
    private static final String PASSWORD = PropertiesUtil.getString("spring.datasource.password");

    /**
     * 数据库连接,定义为全局变量,方便调用
     */
    private Connection con;

    //导入驱动,静态代码块的作用为只运行一次,异常无法向上抛出,只能及时处理
    static {
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            //打印异常相关信息
            e.printStackTrace();
        }
    }

    /**
     * 无参构造方法,连接数据库
     */
    public DataBase() {
        try {
            con = DriverManager.getConnection(URL, NAME, PASSWORD);
        } catch (SQLException throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 数据查找,返回查找的内容,向上抛异常
     *
     * @param sql
     * @param object
     * @return
     * @throws SQLException
     */
    public ResultSet executeSQL(String sql, Object... object) throws SQLException {
        PreparedStatement ps = con.prepareStatement(sql);
        for (int i = 0; i < object.length; i++) {
            //ps传入参数的下标是从1开始
            ps.setObject(i + 1, object[i]);
        }
        //返回结果集
        return ps.executeQuery();
    }

    /**
     * 关闭数据库连接
     *
     * @throws SQLException
     */
    public void close() throws SQLException {
        con.close();
    }

    /**
     * 设置 AutoCommit 模式为 false
     *
     * @throws SQLException
     */
    public void setAutoCommit(boolean flag) throws SQLException {
        // 设置 AutoCommit 模式
        con.setAutoCommit(flag);
    }

    /**
     * 事务提交
     *
     * @throws SQLException
     */
    public void commit() throws SQLException {
        // 手动提交事务
        con.commit();
    }

    /**
     * 事务回滚
     *
     * @throws SQLException
     */
    public void rollback() throws SQLException {
        con.rollback();
    }
}

批量插入数据

public class BulkCopyUtil {

    /**
     * 批量插入数据
     *
     * @param tableName 表名
     * @param list      数据集合
     * @throws SQLException
     */
    public static <T> void insertBatch(String tableName, List<T> list) throws Exception {
        // 查询出空值用于构建 CachedRowSetImpl 对象以省去列映射的步骤
        DataBase dataBase = new DataBase();
        // 从源表中获取数据作为 ResultSet
        ResultSet resultSet = dataBase.executeSQL("select * from " + tableName + " where 1=0");
        CachedRowSetImpl crs = new CachedRowSetImpl();
        crs.populate(resultSet);
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        String[] dbFieldNames = new String[columnCount];
        for (int i = 1; i <= columnCount; i++) {
            dbFieldNames[i-1] = metaData.getColumnName(i);
        }
        // 循环批量插入
        for (T t : list) {
            if (ObjectUtil.isNotEmpty(t)) {
                // 移动指针到“插入行”,插入行是一个虚拟行
                crs.moveToInsertRow();
                // 向 CachedRowSet 对象插入一条数据
                populate(crs, t, dbFieldNames);
                // 插入虚拟行
                crs.insertRow();
                // 移动指针到当前行
                crs.moveToCurrentRow();
            }
        }
        // 进行批量插入
        bulkCopyHelp(dataBase, crs, tableName, list.size());
    }

    /**
     * 批量插入数据
     *
     * @param dataBase  数据库连接相关操作
     * @param crs       CachedRowSet
     * @param tableName 表名
     * @param size      拷贝列表大小
     */
    public static void bulkCopyHelp(DataBase dataBase, CachedRowSetImpl crs, String tableName, int size) throws
            SQLException {
        // 数据库地址
        String url = PropertiesUtil.getString("spring.datasource.url");
        // 数据库用户名
        String name = PropertiesUtil.getString("spring.datasource.username");
        // 数据库密码
        String password = PropertiesUtil.getString("spring.datasource.password");
        // 数据库连接字符串
        String urlStr = url + ";user=" + name + ";password=" + password;

        // 使用 KeepIdentity 选项和 BatchSize 设置大容量复制对象
        SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
        copyOptions.setKeepIdentity(true);
        copyOptions.setBatchSize(size);
        // 开启数据库事务
        copyOptions.setUseInternalTransaction(true);
        // 设置超时时间
        copyOptions.setBulkCopyTimeout(60000);

        SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(urlStr);
        bulkCopy.setBulkCopyOptions(copyOptions);
        // 设置拷贝目标表名
        bulkCopy.setDestinationTableName(tableName);
        // 将 crs 写入目标
        try {
            // 设置 AutoCommit 模式为 false
            dataBase.setAutoCommit(false);
            // 执行数据库操作
            bulkCopy.writeToServer(crs);
            // 手动提交事务
            dataBase.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            // 回滚
            dataBase.rollback();
        }
        crs.close();
        bulkCopy.close();
    }

    /**
     * 这里主要是通过表的列名,通过反射,拿到待插入对象的属性值
     *
     * @param crs
     * @param record
     * @param dbFieldNames
     * @param <T>
     * @throws Exception
     */
    private static <T> void populate(CachedRowSetImpl crs, T record, String[] dbFieldNames) throws Exception {
        Class<?> clazz = record.getClass();
        for (String fieldName : dbFieldNames) {
            StringBuilder getMethodName = new StringBuilder("get");
            if (fieldName.contains("_")) {
                String[] singleWords = fieldName.split("_");
                for (String singleWord : singleWords) {
                    getMethodName.append(upperFirstChar(singleWord));
                }
            } else {
                getMethodName.append(upperFirstChar(fieldName));
            }
            Method method = clazz.getMethod(getMethodName.toString(), null);
            Object value = method.invoke(record, null);
            updateCrs(crs, fieldName, value);
        }
    }

    /**
     * 根据数据值的类型,将值设置到rowset里--这里value是否为空,都要做crs.update操作,否则会出bug
     *
     * @param crs
     * @param dbFieldName
     * @param value
     * @throws SQLException
     */
    private static void updateCrs(CachedRowSetImpl crs, String dbFieldName, Object value) throws SQLException {
        if (value instanceof String) {
            crs.updateString(dbFieldName, (String) value);
        } else if (value instanceof Integer) {
            crs.updateInt(dbFieldName, (int) value);
        } else if (value instanceof Double) {
            crs.updateDouble(dbFieldName, (double) value);
        } else if (value instanceof Long) {
            crs.updateLong(dbFieldName, (long) value);
        } else if (value instanceof Float) {
            crs.updateFloat(dbFieldName, (float) value);
        } else if (value instanceof Timestamp) {
            crs.updateTimestamp(dbFieldName, (Timestamp) value);
        } else if (value instanceof java.util.Date) {
            crs.updateDate(dbFieldName, new java.sql.Date(((java.util.Date) value).getTime()));
        } else {
            crs.updateObject(dbFieldName, value);
        }
    }
	/**
     * 首字母大写
     * @param camelCaseStr
     * @return
     */
    private static String upperFirstChar(String camelCaseStr) {
        return camelCaseStr.substring(0, 1).toUpperCase() + camelCaseStr.substring(1);
    }
}

备注(数据库连接取值)

# 配置数据源
spring:
  datasource:
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://ip:port;DatabaseName=collection
    username: sa
    password: 123456
          

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

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

相关文章

第17篇 使用数码管实现计数器___ARM汇编语言程序<四>

Q&#xff1a;如何使用定时器实现数码管循环计数器&#xff1f; A&#xff1a;DE1-SoC_Computer系统有许多硬件定时器&#xff0c;本次实验使用A9 Private Timer定时器实现延时&#xff1a;定时器首先向Load寄存器写入计数值&#xff0c;然后向Control寄存器中的使能位E写1来启…

SSM 进销存系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…

通过Cephadm工具搭建Ceph分布式存储以及通过文件系统形式进行挂载的步骤

1、什么是Ceph Ceph是一种开源、分布式存储系统&#xff0c;旨在提供卓越的性能、可靠性和可伸缩性。它是为了解决大规模数据存储问题而设计的&#xff0c;使得用户可以在无需特定硬件支持的前提下&#xff0c;通过普通的硬件设备来部署和管理存储解决方案。Ceph的灵活性和设计…

【Rust自学】8.4. String类型 Pt.2:字节、标量值、字形簇以及字符串的各类操作

8.4.0. 本章内容 第八章主要讲的是Rust中常见的集合。Rust中提供了很多集合类型的数据结构&#xff0c;这些集合可以包含很多值。但是第八章所讲的集合与数组和元组有所不同。 第八章中的集合是存储在堆内存上而非栈内存上的&#xff0c;这也意味着这些集合的数据大小无需在编…

svn分支相关操作(小乌龟操作版)

在开发工作中进行分支开发&#xff0c;涉及新建分支&#xff0c;分支切换&#xff0c;合并分支等 新建远程分支 右键选择branch/tagert按钮 命名分支的路径名称 点击确定后远程分支就会生成一个当时命名的文件夹&#xff08;开发分支&#xff09; 分支切换 一般在开发阶段&a…

24年收尾之作------动态规划<六> 子序列问题(含对应LeetcodeOJ题)

目录 引例 经典LeetCode OJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 引例 OJ传送门 LeetCode<300>最长递增子序列 画图分析: 使用动态规划解决 1.状态表示 dp[i]表示以i位置元素为结尾的子序列中&#xff0c;最长递增子序列的长度 2.…

蓝牙|软件 Qualcomm S7 Sound Platform开发系列之初级入门指南

本文适用范围 ADK24.2~ 问题/功能描述 S7开发环境搭建与编译介绍 实现方案 本文介绍适用于windows平台Application部分,audio ss的说明会在下一篇文章在做说明,Linux平台如果不进行AI算法的开发,个人认知是没有必要配置,若是做服务器倒是不错的选择.因为编译完成后烧录调试还…

Redis - 4 ( 9000 字 Redis 入门级教程 )

一&#xff1a; Zset 有序集合 1.1 常用命令 有序集合在 Redis 数据结构中相较于字符串、列表、哈希和集合稍显陌生。它继承了集合中元素不允许重复的特点&#xff0c;但与集合不同的是&#xff0c;有序集合的每个元素都关联一个唯一的浮点分数&#xff08;score&#xff09;…

ubuntu 使用samba与windows共享文件[注意权限配置]

在Ubuntu上使用Samba服务与Windows系统共享文件&#xff0c;需要正确配置Samba服务以及相应的权限。以下是详细的步骤&#xff1a; 安装Samba 首先&#xff0c;确保你的Ubuntu系统上安装了Samba服务。 sudo apt update sudo apt install samba配置Samba 安装完成后&#xff0c…

打印进度条

文章目录 1.Python语言实现(1)黑白色(2)彩色&#xff1a;蓝色 2.C语言实现(1)黑白颜色(2)彩色版&#xff1a;红绿色 1.Python语言实现 (1)黑白色 import sys import timedef progress_bar(percentage, width50):"""打印进度条:param percentage: 当前进度百分比…

深度解析 LDA 与聚类结合的文本主题分析实战

🌟作者简介:热爱数据分析,学习Python、Stata、SPSS等统计语言的小高同学~🍊个人主页:小高要坚强的博客🍓当前专栏:《Python之文本分析》🍎本文内容:深度解析 LDA 与聚类结合的文本主题分析实战🌸作者“三要”格言:要坚强、要努力、要学习 目录 引言 技术框架…

点跟踪基准最早的论文学习解读:TAP-Vid: A Benchmark for Tracking Any Point in a Video—前置基础

TAP-Vid: A Benchmark for Tracking Any Point in a Video— TAP-Vid&#xff1a;跟踪视频中任意点的基准、 学习这一篇文章的本来的目的是为了学习一下TAP-NET便于理解后面用到的TAPIR方法的使用。 文章目录 TAP-Vid: A Benchmark for Tracking Any Point in a Video— TAP-V…

C进阶-字符串与内存函数介绍(另加2道典型面试题)

满意的话&#xff0c;记得一键三连哦&#xff01; 我们先看2道面试题 第一道&#xff1a; 我们画图理解&#xff1a; pa&#xff0c;先使用再&#xff0c;pa开始指向a【0】&#xff0c;之后pa向下移动一位&#xff0c;再解引用&#xff0c;指向a【1】&#xff0c;a【1】又指向…

PH47代码框架 24241231 重要更新

仪式感一下&#xff1a;2024年最后一天&#xff0c;发布 PH47 代码框架的一次重要更新。当然这并不是有意的&#xff0c;而是直到现在才把更新的所有工作全部做完&#xff08;希望确实如此&#xff09;。 本次更新要点&#xff1a; 1、加入多IMU支持。本次更新正式加入对 MPU65…

idea报错:There is not enough memory to perform the requested operation.

文章目录 一、问题描述二、先解决三、后原因&#xff08;了解&#xff09; 一、问题描述 就是在使用 IDEA 写代码时&#xff0c;IDEA 可能会弹一个窗&#xff0c;大概提示你目前使用的 IDEA 内存不足&#xff0c;其实就是提醒你 JVM 的内存不够了&#xff0c;需要重新分配。弹…

Python用K-Means均值聚类、LRFMC模型对航空公司客户数据价值可视化分析指标应用|数据分享...

全文链接&#xff1a;https://tecdat.cn/?p38708 分析师&#xff1a;Yuling Fang 信息时代的来临使得企业营销焦点从产品中心转向客户中心&#xff0c;客户关系管理成为企业的核心问题&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 客户关系管理的关键是客…

Linux umami网站统计工具自定义API开发

Linux umami网站统计工具自定义API开发 一、src/queries/analytics/下添加调用sql查询文件&#xff1a;二、src/queries/index.js文件中增加导出模块内容&#xff1a;三、src/pages/api/下根据目录添加接口方法文件&#xff1a;四、构建项目&#xff0c;启动。1、到umami目录&a…

基于SpringBoot的实验室信息管理系统【源码+文档+部署讲解】

系统介绍 视频演示 基于SpringBootVue实现的实验室信息管理系统采用前后端分离的架构方式&#xff0c;系统分为管理员、老师、用户三种角色&#xff0c;实现了用户管理、设备管理、实验室查询、公告、课程、实验室耗材管理、我的等功能 技术选型 开发工具&#xff1a;idea2…

【openGauss】正则表达式次数符号“{}“在ORACLE和openGauss中的差异

一、前言 正则作为一种常用的字符串处理方式&#xff0c;在各种开发语言&#xff0c;甚至数据库中&#xff0c;都有自带的正则函数。但是正则函数有很多标准&#xff0c;不同标准对正则表达式的解析方式不一样&#xff0c;本次在迁移一个ORACLE数据库到openGauss时发现了一个关…

SSM-Spring-IOC/DI对应的配置开发

目录 一、IOC 控制反转 1.什么是控制反转呢 2. Spring和IOC之间的关系是什么呢? 3.IOC容器的作用以及内部存放的是什么? 4.当IOC容器中创建好service和dao对象后&#xff0c;程序能正确执行么? 5.Spring 容器管理什么内容&#xff1f; 6.如何将需要管理的对象交给 …