JPA实现批量保存

手写insert方法,通过拼接的方式实现,批量插入

通过获取实体类上@注解,获取字段名称,

以及通过拼接的方式使用获取对象的属性值

import io.lettuce.core.dynamic.annotation.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.persistence.*;
import javax.transaction.Transactional;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Transactional
@Slf4j
public class BatchService {

    @PersistenceContext
    private EntityManager entityManager;

    //配置文件中每次批量提交的数量
    private long batchSize = 500;

    public BatchService(){

    }


    public String getTableName(Class<?> entityClass) {
        Table tableAnnotation = entityClass.getAnnotation(Table.class);
        if (tableAnnotation != null) {
            return tableAnnotation.name();
        }
        return null;
    }

    public String[] getColumnNames(Class<?> entityClass) {
        List<String> columns = new ArrayList<>();
        Field[] fields = entityClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class) && !field.isAnnotationPresent(Id.class)) {
                Column columnAnnotation = field.getAnnotation(Column.class);
                String name = columnAnnotation.name();
                columns.add(name);
            }
        }
        return columns.toArray(new String[fields.length-1]);
    }
    public String[] getColumn(Class<?> entityClass) {
        List<String> columns = new ArrayList<>();
        Field[] fields = entityClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class) && !field.isAnnotationPresent(Id.class)) {
                String columnName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                columns.add(columnName);
            }
        }
        return columns.toArray(new String[fields.length-1]);
    }

    public String[] getColumnLowwer(Class<?> entityClass) {
        List<String> columns = new ArrayList<>();
        Field[] fields = entityClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class) && !field.isAnnotationPresent(Id.class)) {
                String columnName = field.getName();
                columns.add(columnName);
            }
        }
        return columns.toArray(new String[fields.length-1]);
    }


    @Transactional
    public <T> List<T> saveAll(Class<?> entityClass,List<T> list)  {
        String tableName = getTableName(entityClass);
        String[] columns = getColumnNames(entityClass);
        String[] column = getColumn(entityClass);
        String[] columnLowwer = getColumnLowwer(entityClass);
        StringBuilder sb = into(tableName, columns);
        int i = 0;
        for (T entity : list) {
            i++;
            if (i > 1) {
                sb.append(",");
            }
            sb.append("(");
            for (int j = 0; j < column.length; j++) {
                try {
                    Class<?> type = entityClass.getDeclaredField(columnLowwer[j]).getType();
                    Object value = entity.getClass().getMethod("get" + column[j]).invoke(entity);
                   if (value == null){
                       sb.append(String.format("%s", null));
                   }else {
                       sb.append(String.format("'%s'", transferType(type,value)));
                   }
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                }
                if (j < columns.length - 1) {
                    sb.append(",");
                }
            }
            sb.append(")");
            // 每一千条执行一次
            if (i >= 1000) {
                log.info(sb.toString());
                entityManager.createNativeQuery(sb.toString() + ";").executeUpdate();
                i = 0;
                sb = into(tableName, columns);
            }
        }
        if (i > 0) {
            entityManager.createNativeQuery(sb.toString() + ";").executeUpdate();
        }
        return list;
    }

    // SQL前半段方法提取
    private StringBuilder into(String tableName, String[] columns) {
        StringBuilder sb = new StringBuilder();
        sb.append("insert into ").append(tableName).append("(");
        for (int i = 0; i < columns.length; i++) {
            sb.append(columns[i]);
            if (i < columns.length - 1) {
                sb.append(",");
            }
        }
        sb.append(") values");
        return sb;
    }

    private Object transferType(Class<?> type,Object value){
        if(type.getTypeName().equals("java.util.Date")){
            Date date= (Date) value;
            value = SysDateUtils.date2Str(date,"yyyy-MM-dd HH:mm:ss");
        }
        return value;
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
回答: 如果您在使用JPA进行批量插入数据时遇到了速度慢的问题,可以尝试以下几个方法来提高性能。首先,您可以在应用的配置文件中进行一些调整。通过设置`spring.jpa.properties.hibernate.jdbc.batch_size`属性,您可以指定批量操作的大小,这可以减少与数据库的通信次数,从而提高性能。另外,您还可以设置`spring.jpa.properties.hibernate.jdbc.batch_versioned_data`属性为`true`,以告诉Hibernate JDBC驱动程序在执行批量更新时返回正确的受影响行数。此外,您可以开启批量插入和批量更新功能,通过设置`spring.jpa.properties.hibernate.order_inserts`和`spring.jpa.properties.hibernate.order_updates`属性为`true`来实现。\[1\] 其次,您可以调整数据库的配置。对于国产神通数据库,您可以在jdbc_url中添加`rewriteBatchedStatements=TRUE`参数来开启批量操作的优化。这可以提高批量插入的性能。\[2\] 最后,您还可以创建一个自定义的Repository接口,并继承`JpaRepository`和`JpaSpecificationExecutor`接口。在该接口中,您可以定义一个`batchSave`方法,使用`@Transactional`注解来确保批量插入操作在一个事务中执行。这样可以提高性能并减少数据库的负载。\[3\] 通过以上方法的调整,您应该能够提高JPA批量插入数据的速度。希望对您有帮助! #### 引用[.reference_title] - *1* *2* *3* [Spring Data JPA批量插入过慢及其优化 —— 自定义Repository](https://blog.csdn.net/tfstone/article/details/113741890)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maserati477

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值