以后谁在用Mybatis的foreach进行大批量操作,谁就辞职

**

以后谁在用Mybatis的foreach进行大批量操作,谁就辞职

**
最近进行数据库大批量插入操作,有人竟然使用Mybatis的foreach去执行,我大呼失策,为什么要用foreach进行数据库大批量操作呢,就连Mybatis官方也不建议使用foreach去进行大批量数据的操作,并且给出了解决方案.

有兴趣的可以查看,找到Batch Insert Support 标签里的内容.

哎,还要优化同事的代码,烦死了!!!****

package com.eeetuo.Foreach;

import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.service.IService;
import com.eeetuo.Foreach.config.MyBatisJoinApplication;
import com.eeetuo.entity.TagLastValueEntity;
import com.eeetuo.entity.TagValueEntity;
import com.eeetuo.Foreach.enums.SqlForeachEnums;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;


@Service
public class ForeachByMyBatis {

    @Resource
    MyBatisJoinApplication myBatisJoinApplication;

    @Resource
    DataSourceProperties properties;

    @Resource
    IService<TagLastValueEntity> iService;


    public void BatchInsertSupport(List<TagValueEntity> records, Integer sqlCode) {

        Connection connection = null;
        try {
            connection = DriverManager.getConnection(myBatisJoinApplication.getConnection(),properties.getUsername(),properties.getPassword());
            connection.setAutoCommit(false);
            PreparedStatement ps = connection.prepareStatement(
                    SqlForeachEnums.getSqlByCode(sqlCode));
            for (int i = 0; i < records.size(); i++) {
                ps.setString(1,"1");
                ps.setString(2, String.valueOf(LocalDateTime.now()));
                ps.setString(3, records.get(i).getTagValue());
                ps.setLong(4,records.get(i).getTagId());
                ps.setLong(5,records.get(i).getDevinceId());

                //如果选用第二条sql,则添加当天时间和小时时间
                if (sqlCode ==2){
                    ps.setString(6, String.valueOf(LocalDate.now()));
                    ps.setString(7, String.valueOf(LocalDateTime.now().getHour()));
                }
                ps.addBatch();
            }
            ps.executeBatch();
            connection.commit();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    //true:代表添加  false:代表修改
    public boolean saveOrUpdate(TagLastValueEntity entity){

        TableInfo tableInfo = TableInfoHelper.getTableInfo(TagLastValueEntity.class);
        Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty());
        return ObjectUtils.isEmpty(idVal);
    }


}

我们看到新建一个进行操作批量的类,核心的方法就是BatchInsertSupport,其中DriverManager.getConnection()中的值其实是数据库连接url和用户名密码,在这里我是用的yml配置文件的方式来进行操作的,因为我懒,不想到时候如果更换数据库地址而再次改代码.

package com.eeetuo.Foreach.config;

import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import static org.apache.commons.lang3.StringUtils.isEmpty;


@Data
@Component
@ConfigurationProperties(prefix = "join")
public class MyBatisJoinApplication {

    /** 数据库类型*/
    private String dbType;

    /** 数据库url*/
    private String dbUrl;

    /** 数据库名字*/
    private String dbName;

    /** 数据库连接*/
    private String Connection;


    public String getConnection(){
       if (isAllEmpty(getDbType(),getDbUrl(),getDbName())){
           return "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true";
       }else {
           return "jdbc:"+getDbType()+"://"+getDbUrl()+"/"+getDbName()+"?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true";
       }
    }

    public static boolean isAllEmpty(CharSequence... css) {
        if (ArrayUtils.isEmpty(css)) {
            return true;
        } else {
            CharSequence[] var1 = css;
            int var2 = css.length;

            for(int var3 = 0; var3 < var2; ++var3) {
                CharSequence cs = var1[var3];
                if (isEmpty(cs)) {
                    return true;
                }
            }

            return false;
        }
    }


}

需要注意的一点是PreparedStatement 在进行set方法中的参数所代表的意思!!!

需要注意的是jdbc连接必须要有 rewriteBatchedStatements=true

关于rewriteBatchedStatements这个参数介绍:

MySQL的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。
MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。
只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL
另外这个选项对INSERT/UPDATE/DELETE都有效

参数也很明了,records就是需要我们所需要的参数集,sqlCode就是具体的sql语句,那具体是需要哪条sql语句就需要我们创建一个枚举来判断一下了,接下来就是创建枚举类了.

package com.eeetuo.Foreach.enums;

import lombok.Getter;

@Getter
public enum  SqlForeachEnums {

    TAG_VALUE_SQL(1,"insert into tb_tag_value (state,created_time,tag_value,tag_id,devince_id) values(?,?,?,?,?)"),
    TAG_HOUR_VALUE_SQL(2,"insert into tb_tag_hour_value (state,created_time,tag_value,tag_id,devince_id,day_time,hour_time) values(?,?,?,?,?,?,?)"),

    TAG_LAST_VALUE_ADD_SQL(3,"insert into tb_tag_last_value (state,created_time,tag_value,tag_id,devince_id) values(?,?,?,?,?)"),
    TAG_LAST_VALUE_UPDATE_SQL(4,"update tb_tag_last_value set state=?,created_time=?,tag_value=?,tag_id=?,devince_id=? where id=?");

    private Integer sqlCode;

    private String sql;

    SqlForeachEnums(Integer sqlCode,String sql){
        this.sqlCode=sqlCode;
        this.sql=sql;
    }

    public static String getSqlByCode(Integer sqlCode){

        String sql="";

        //判断如果code相同,获取对应的sql语句
        for (SqlForeachEnums value : SqlForeachEnums.values()) {
            if (value.sqlCode.equals(sqlCode)){
                sql= value.sql;
                break;
            }
        }

        return sql;

    }


}

在这个枚举类中核心的就是getSqlByCode这个方法,根据参数sqlCode判断选择哪条sql语句

进行到这里,批量操作的工作就已经完成了,接下来就是业务上面的工作了,累呀!!!
希望各位能多给提点意见,小弟好规避bug,拜拜儿!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值