`
dannyhz
  • 浏览: 387865 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

批量插入数据

 
阅读更多
https://www.cnblogs.com/LiQ0116/p/7389049.html

引用


一、业务背景

  由于需要从A数据库提取大量数据同步到B系统,采用了tomikos+jta进行分布式事务管理,先将系统数据源切换到数据提供方,将需要同步的数据查询出来,然后再将系统数据源切换到数据接收方,进行批量的插入和更新操作,

关于数据源的切换可以参考之前的文章《spring+springMVC+Mybatis架构下采用AbstractRoutingDataSource、atomikos、JTA实现多数据源灵活切换以及分布式事务管理》



二、批量插入的具体实现

  1.查询需要同步的数据:

复制代码
    @Autowired
    SysPersonPOMapper sysPersonPOMapper;
   
    public void dataDs(){
        //根据具体情况可以创建查询条件或者采用自定义的Mapper进行查询
        SysPersonPOExample sysPersonPOExample = new SysPersonPOExample();
        sysPersonPOExample.createCriteria().andIsDeleteEqualTo(false);
        //查询需要同步的数据
        List<SysPersonPO> persons = sysPersonPOMapper.selectByExample(sysPersonPOExample);
    }
复制代码
  2.将不能进行遍历的PO实体对象转为Map,此处有一个前提条件:MySQL中的表字段是按全大写加下划线命名,实体类PO映射字段为对应的标准驼峰命名方式,进行PO到Map

的转换时,会遵循这一规则。

复制代码
    @Autowired
    SysPersonPOMapper sysPersonPOMapper;
   
    public void dataDs() throws Exception{
        //1.查询需要同步的数据
        //根据具体情况可以创建查询条件或者采用自定义的Mapper进行查询
        SysPersonPOExample sysPersonPOExample = new SysPersonPOExample();
        sysPersonPOExample.createCriteria().andIsDeleteEqualTo(false);
        //查询需要同步的数据
        List<SysPersonPO> persons = sysPersonPOMapper.selectByExample(sysPersonPOExample);
       
        //2.将不能进行遍历的PO实体对象转为Map
       
        //用于存放转换后的对象的List
        List<Map<String,Object>> insertItems = Lists.newArrayList();
        for (SysPersonPO sysPersonPO : persons) {
            Map<String,Object> insertItem = BeanMapUtil.convertBean2MapWithUnderscoreName(sysPersonPO);
            insertItems.add(insertItem);
        }
    }
复制代码
  

BeanMapUtil类,PO到Map的转换方法,基于类反射技术:
复制代码
import com.fms.common.utils.other.StringUtil;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;


public class BeanMapUtil {

  @SuppressWarnings({"unchecked", "rawtypes"})
    public static Map convertBean2MapWithUnderscoreName(Object bean) throws Exception {
        Map returnMap = null;
        try {
            Class type = bean.getClass();
            returnMap = new HashMap();
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
            PropertyDescriptor[] propertyDescriptors = beanInfo
                    .getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equalsIgnoreCase("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = readMethod.invoke(bean, new Object[0]);
                    returnMap.put( StringUtil.underscoreName(propertyName), result);
                }
            }
        } catch (Exception e) {
            // 解析错误时抛出服务器异常 记录日志
            throw new Exception("从bean转换为map时异常!", e);
        }
        return returnMap;
    }

}
复制代码


StringUtil类,标准驼峰命名与数据库下划线命名之间转换的方法:

复制代码
public class StringUtil {

   /**
     * 将驼峰式命名的字符串转换为下划线大写方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br>
     * 例如:HelloWorld->HELLO_WORLD
     *
     * @param name 转换前的驼峰式命名的字符串
     * @return 转换后下划线大写方式命名的字符串
     */
    public static String underscoreName(String name) {
        StringBuilder result = new StringBuilder();
        if (name != null && name.length() > 0) {
            // 将第一个字符处理成大写
            result.append(name.substring(0, 1).toUpperCase());
            // 循环处理其余字符
            for (int i = 1; i < name.length(); i++) {
                String s = name.substring(i, i + 1);
                // 在大写字母前添加下划线
                if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) {
                    result.append("_");
                }
                // 其他字符直接转成大写
                result.append(s.toUpperCase());
            }
        }
        return result.toString();
    }
}
复制代码




3.编写Mybatis映射文件fmsDataDsMapper.xml

复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.fms.common.dao.fmsDataDsMapper">

<!-- 批量插入,传入表名和需要插入的数据的集合 -->
    <insert id="insertDatas" parameterType="map">
       insert into ${table_name}
       <foreach collection="fields" index="field"  item="fieldVal" separator="," open="(" close=")">
                ${field}
       </foreach>
               values 
       <foreach collection="list" index="index" item="record" separator="," >
            <foreach collection="record" index="key"  item="item" separator="," open="(" close=")">
                #{item}
            </foreach>
        </foreach>
    </insert>

</mapper>
复制代码


4.调用sqlsession相关API的insert方法插入数据:

复制代码
    @Autowired
    SysPersonPOMapper sysPersonPOMapper;
   
    public void dataDs() throws Exception{
        //1.查询需要同步的数据
        //根据具体情况可以创建查询条件或者采用自定义的Mapper进行查询
        SysPersonPOExample sysPersonPOExample = new SysPersonPOExample();
        sysPersonPOExample.createCriteria().andIsDeleteEqualTo(false);
        //查询需要同步的数据
        List<SysPersonPO> persons = sysPersonPOMapper.selectByExample(sysPersonPOExample);
       
        //2.将不能进行遍历的PO实体对象转为Map
       
        //用于存放转换后的对象的List
        List<Map<String,Object>> insertItems = Lists.newArrayList();
        for (SysPersonPO sysPersonPO : persons) {
            Map<String,Object> insertItem = BeanMapUtil.convertBean2MapWithUnderscoreName(sysPersonPO);
            insertItems.add(insertItem);
        }
       
        //3.插入数据
        insertDatas(insertItems,"sys_person");
    }
   
   
    @Autowired
    SqlSessionTemplate sqlSessionTemplate;
    private String dataDsNameSpace = "com.fms.common.dao.fmsDataDsMapper";
    private void insertDatas(List<Map<String,Object>> insertItems, String tableName){
        if (!insertItems.isEmpty()) {
            Map<String,Object> params = Maps.newHashMap();
       //这里把数据分成每1000条执行一次,可根据实际情况进行调整
            int count = insertItems.size() / 1000;
            int yu = insertItems.size() % 1000;
            for (int i = 0; i <= count; i++) {
                List<Map<String,Object>> subList = Lists.newArrayList();
                if (i == count) {
                    if(yu != 0){
                        subList = insertItems.subList(i * 1000, 1000 * i + yu);
                    }else {
                        continue;
                    }
                } else {
                    subList = insertItems.subList(i * 1000, 1000 * (i + 1));
                }
                params.put("table_name", tableName);
                params.put("fields", subList.get(0));
                params.put("list", subList);
                sqlSessionTemplate.insert(dataDsNameSpace+".insertDatas", params);
            }
        }
    }
复制代码


三 、批量更新的具体实现

  通常我们根据主键更新时的语句是 update  table_name set column1 = val1 , column2 = val2 [,......] where id = ?  或者使用Mybatis提供的updateByPrimaryKey接口,

  当我们希望一次性更新大量数据时,每条SQL只能执行一条更新,MySQL支持另外一种更新方式,让我们可以实现通过一条SQL语句一次性更新多条 根据主键更新的记录:

  ON DUPLICATE KEY UPDATE

  注意:这不同于在满足where条件时将某个table中的某一字段全部更新为同一各值,而是每条记录修改后的值都不一样。



1.构建需要更新的数据,需要注意的是如果PO中存在不想要更新的字段,你有两种处理方式,一种是将该字段的值在此处设为数据库中原来的值,另一种方式就是在进行Map转换时,

不将此字段构建到Map中,这只需要对convertBean2MapWithUnderscoreName方法做一些小的修改,你可以把不需要保留的字段作为参数传给它,然后在转换的时候过滤掉(主键不能省略)。

复制代码
        //4.构建批量更新的数据
        //用于存放转换后的对象的List
        List<Map<String,Object>> updateItems = Lists.newArrayList();
        for (SysPersonPO sysPersonPO : persons) {
            sysPersonPO.setCode(sysPersonPO.getCode()+"updateTest");
            Map<String,Object> updatetItem = BeanMapUtil.convertBean2MapWithUnderscoreName(sysPersonPO);
            updateItems.add(updatetItem);
        }
复制代码


2.编写Mybatis映射文件fmsDataDsMapper.xml

复制代码
  <!-- 根据主键批量更新某个字段,传入表名和需要更新的数据的集合 -->
    <insert id="updateDatas" parameterType="map">
       INSERT INTO ${table_name}
       <foreach collection="fields" index="field"  item="fieldVal" separator="," open="(" close=")">
                ${field}
       </foreach>
               VALUES 
       <foreach collection="list" index="index" item="record" separator="," >
            <foreach collection="record" index="key"  item="item" separator="," open="(" close=")">
                #{item}
            </foreach>
        </foreach>
        ON DUPLICATE KEY UPDATE
        <foreach collection="fields" index="field"  item="fieldVal" separator=",">
                ${field}=VALUES(${field})
       </foreach>
    </insert>
复制代码


3.更新数据

复制代码
//5.更新数据
updateDatas(updateItems,"sys_person");


private void updateDatas(List<Map<String,Object>> updateItems, String tableName){
        if (!updateItems.isEmpty()) {
            Map<String,Object> params = Maps.newHashMap();
       //这里将数据分成每1000条执行一次,可根据实际情况调整
            int count = updateItems.size() / 1000;
            int yu = updateItems.size() % 1000;
            for (int i = 0; i <= count; i++) {
                List<Map<String,Object>> subList = Lists.newArrayList();
                if (i == count) {
                    if(yu != 0){
                        subList = updateItems.subList(i * 1000, 1000 * i + yu);
                    }else {
                        continue;
                    }
                } else {
                    subList = updateItems.subList(i * 1000, 1000 * (i + 1));
                }
                params.put("table_name", tableName);
                params.put("fields", subList.get(0));
                params.put("list", subList);
                sqlSessionTemplate.insert(dataDsNameSpace+".updateDatas", params);
            }
        }
    }
复制代码

分享到:
评论

相关推荐

    C# 批量插入数据方式

    在C#编程中,批量插入数据是数据库操作中常见的需求,尤其在处理大量数据时,为了提高效率,避免频繁的数据库交互,批量插入是必不可少的技巧。本篇将详细讲解如何在C#中实现批量插入数据,以及涉及的相关知识点。 ...

    sql下三种批量插入数据的方法

    本文将介绍三种批量插入数据的方法。第一种方法是使用循环语句逐个将数据项插入到数据库中;第二种方法使用的是SqlBulkCopy,使您可以用其他源的数据有效批量加载 SQL Server 表;第三种使用的方法是sql server中的...

    jdbc-批量插入数据

    本文将深入探讨如何使用JDBC进行批量插入数据,这在处理大量数据时能显著提高性能。 批量插入数据是数据库操作中常见的一种优化策略,特别是在数据分析、数据迁移或大数据处理等场景。传统的单条插入方式可能会导致...

    批量插入数据到Oracle数据库Demo

    本教程将详细讲解如何进行批量插入数据到Oracle数据库,以提高数据导入的效率。 批量插入数据到Oracle数据库通常比单条插入更有效率,因为它减少了与数据库的交互次数,降低了网络延迟,并减少了系统资源的占用。...

    批量插入数据软件-含详细流程说明

    当我们需要快速填充大量的测试数据或初始化数据库时,批量插入数据软件就显得尤为实用。本篇将详细阐述如何使用一款专业的数据库智能创建数据软件,它具备自动导入百万条数据的能力,并且允许用户自定义数据格式,...

    oracle 批量插入数据存储过程

    oracle 批量插入数据存储过程。亲测好用。支持 plsql ,toad,等数据库分析软件。主要包括变量的定义,循环及游标的使用等, 亲测好用

    C# Oracle批量插入数据进度条的实现代码

    考虑到当Excel数据量较大时,循环Insert语句效率太低,故采用批量插入的方法。在插入操作运行时,会造成系统短暂的“卡死”现象。为了让用户知道插入的状态,需要制作一个进度条来显示插入的进度。 批量插入 项目中...

    Spring JdbcDaoSupport 批量插入数据

    本文将深入探讨如何利用`JdbcDaoSupport`进行批量插入数据的操作,以及其背后的原理和源码分析。 首先,`JdbcDaoSupport`是`AbstractJdbcDaoSupport`的子类,它提供了对JDBC访问的便捷封装,允许开发者无需直接管理...

    EasyExcel 并发读取文件字段并进行校验,数据写入到新文件,批量插入数据到数据库

    5. **批量插入数据到数据库** 在数据处理过程中,往往还需要将数据批量插入到数据库。EasyExcel提供了一个`executeBatchInsert`方法,可以配合JDBC或其他ORM框架如MyBatis,将数据批量插入到数据库。首先,我们需要...

    Delphi批量插入数据库数据..rar

    本压缩包“Delphi批量插入数据库数据”可能包含了一个或多个示例代码,用于演示如何在Delphi中高效地向数据库批量插入数据。 批量插入数据是数据库操作中的常见需求,尤其是在处理大量数据时,为了提高效率和减少...

    Java实现mybatis批量插入数据到Oracle

    本篇文章将详细介绍如何利用Java和MyBatis实现批量插入数据到Oracle数据库中。 首先,我们需要理解Oracle数据库的一些基本概念。Oracle是世界上最流行的商业关系型数据库管理系统之一,以其强大的功能和高可靠性而...

    ASP 批量插入数据

    在ASP(Active Server Pages)开发中,批量插入数据是一个常见的需求,特别是在处理大量记录时,为了提高效率,避免频繁的数据库交互,批量插入是必不可少的技术。本文将详细讲解如何在ASP中实现批量插入数据,以及...

    支持批量插入的Delphi数据输入程序.rar

    支持批量插入的Delphi数据输入程序,配合数据实现的数据批量输入程序,程序的原型是一个学生管理程序,用来输入学生的基本信息,本程序添加了批量插入数据的功能,可看作是一个批量插入数据的实例吧。相关的代码: ...

    C#SqlBulkcopy批量插入数据

    在.NET框架中,C#提供了一个非常强大的工具——SqlBulkCopy类,用于高效地将大量数据从一个数据源批量插入到SQL Server数据库中。相比于传统的单条INSERT INTO语句,SqlBulkCopy在处理大规模数据导入时能显著提高...

    ACCESS和SQL批量插入数据工具

    这款工具专为数据库管理员和开发人员设计,用于快速、高效地向ACCESS和SQL Server数据库中批量插入数据,尤其在进行负荷测试时,它能显著提高工作效率。 首先,我们来了解一下ACCESS。ACCESS是Microsoft Office套件...

    Hbase笔记 —— 利用JavaAPI的方式操作Hbase数据库(往hbase的表中批量插入数据).pdf

    在本文档中,我们将深入探讨如何使用Java API与HBase数据库进行交互,特别是关于如何创建表、修改表结构以及批量插入数据。HBase是Apache的一个分布式、可扩展的大数据存储系统,它基于谷歌的Bigtable设计,适用于...

    mybaits 多线程 实现数据批量插入 (运用CountDownLatch实现闭锁)

    在批量插入数据的场景下,可以创建一个CountDownLatch对象,初始化为线程的数量,每个线程处理完自己的数据后调用`countDown()`方法,主线程通过调用`await()`方法等待所有线程完成后再执行后续操作,如提交事务。...

    批量插入数据到数据库请使用MysqlBulkCopy.dll.zip

    最近跟客户做数据对接比较多,发现平常的添加到数据库数据太慢,所以也没少逛论坛。结合论坛上的资料封装...插入数据库数据请使用SqlBackCopy。下载过的朋友我这个帖子行或者不行麻烦给在下评论下,希望能帮更多的人。

    mysql批量插入数据运行脚本

    你需要先创建存储过程,然后调用...存储过程可以通过循环批量插入数据,提高代码的重用性和可维护性。 这样的好处:逻辑封装:复杂的插入逻辑可以封装在存储过程内,易于管理。 灵活性:可以根据参数动态调整插入行为。

    android sqlite 批量插入数据优化代码

    然而,随着数据量的增长,批量插入数据的效率变得至关重要。"android sqlite 批量插入数据优化代码"这个主题正是针对这一需求,探讨如何高效地在SQLite数据库中进行大量数据的插入操作。 首先,我们要理解SQLite的...

Global site tag (gtag.js) - Google Analytics