Postgresql 根据model类自动生成插入语句,批量插入数据

Posted 程序媛一枚~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Postgresql 根据model类自动生成插入语句,批量插入数据相关的知识,希望对你有一定的参考价值。

Postgresql 根据model类自动生成插入语句,批量插入数据

  1. 所有的类可以继承自一个BaseObject类(非必需);
  2. 数据库表中的字段名及类型必须与Object类中的一一对应;
  3. 调用通用的方法(对数据进行批量插入);

String.format(“insert into %s(%s) values(%s)”, tableName, fieldNames, marks);

主要涉及到应用反射,获取model类的所有字段名;
拼接sql中的字段名,及占位符;
然后再次利用反射对每一个字段设置值。

源码

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.StringJoiner;


/*************************************
 * Class Name: CommonDao
 * Description:〈通用数据Dao〉
 * @author Seminar
 * @Date 2023.01.18
 ************************************/
@Slf4j
public class CommonDao 
    @Autowired
    JdbcTemplate jdbcTemplate;

    /**
     * 根据字段数组拼接问号
     *
     * @param fields 字段数组
     * @return
     */
    protected String getQueryMark(String fields) 
        String[] arr = fields.split(",");
        int len = arr.length;
        StringJoiner joiner = new StringJoiner(",");
        while (len-- > 0) 
            joiner.add("?");
        
        return joiner.toString();
    

    /**
     * 获取表记录总数
     *
     * @param tableName 表名
     * @return 记录总数
     */
    public Integer getTotal(String tableName) 
        return getTotal(tableName, null);
    

    /**
     * 根据条件获取表记录总数
     *
     * @param tableName 表名
     * @param whereSql  关键字
     * @return 记录总数
     */
    public Integer getTotal(String tableName, String whereSql) 
        String sql = String.format("select count(*) as total from %s", tableName);
        if (!StringUtils.isEmpty(whereSql)) 
            sql += " where " + whereSql;
        
        return jdbcTemplate.queryForObject(sql, Integer.class);
    

    /**
     * 判断查询结果集中是否存在某列
     *
     * @param rs         查询结果集
     * @param columnName 列名
     * @return true 存在; false 不存咋
     */
    public boolean isExistColumn(ResultSet rs, String columnName) 
        try 
            if (rs.findColumn(columnName) > 0) 
                return true;
            
         catch (SQLException e) 
            return false;
        
        return false;
    

    /**
     * 根据字段名获取按?拼接的字符串
     *
     * @param fields 字段名,每一个占位一个?,特殊的集合类型,特殊处理
     * @return
     */
    protected String getQueryMark2(String fields) 
        String[] fieldNames = fields.split(",");
        String delimeter = ",";
        StringBuilder sb = new StringBuilder();
        for (String field : fieldNames) 
            if ("geometry".equals(field) || "s_index".equals(field)) 
                sb.append("ST_GeomFromText(?)" + delimeter);
             else 
                sb.append("?" + delimeter);
            
        

        return sb.substring(0, sb.length() - 1);
    

    /**
     * 批量插入通用方法(注意需要Object类中所有字段名与数据库中表列名的一致)
     *
     * @param objs      对象lists
     * @param tableName 插入的表名
     * @param <T>       通用BaseObject类
     */
    public <T> void batchInsertRdClassT(List<T> objs, String tableName) 
        if (objs == null || objs.isEmpty()) 
            return;
        
        String fieldNames = getFieldNames(objs.get(0).getClass());
        String marks = getQueryMark2(fieldNames);
        String sql = String.format("insert into %s(%s) values(%s)", tableName, fieldNames, marks);
        log.info("", sql);
        int[] res = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() 
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException 
                T item = objs.get(i);
                Field[] fieldVals = item.getClass().getDeclaredFields();
                for (int j = 0; j < fieldVals.length; j++) 
                    Field field = fieldVals[j];
                    field.setAccessible(true);

                    try 
                        setValue(ps, j + 1, field.get(item));
                     catch (IllegalAccessException e) 
                        throw new RuntimeException(e);
                    
                
            

            @Override
            public int getBatchSize() 
                return objs.size();
            
        );
    

    /**
     * 对每一个字段设置值
     *
     * @param ps
     * @param index
     * @param column
     * @throws SQLException
     */
    private void setValue(PreparedStatement ps, int index, Object column) throws SQLException 
        if (column == null) 
            ps.setNull(index, 0);
         else 
            if (column instanceof Long) 
                ps.setLong(index, (Long) column);
             else if (column instanceof String) 
                ps.setLong(index, (Long) column);
             else if (column instanceof Integer) 
                ps.setInt(index, (Integer) column);
             else if (column instanceof Double) 
                ps.setDouble(index, (Double) column);
             else if (column instanceof Boolean) 
                ps.setBoolean(index, (Boolean) column);
            
        
    

    /**
     * 获取类的所有字段名,并,拼接
     *
     * @param clazz 实体类名
     * @return
     */
    private static String getFieldNames(Class clazz) 
        Field[] fields = clazz.getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) 
            fieldNames[i] = fields[i].getName();
        
        return StringUtils.join(fieldNames, ",");
    

以上是关于Postgresql 根据model类自动生成插入语句,批量插入数据的主要内容,如果未能解决你的问题,请参考以下文章

django根据已有数据库表生成model类

在 PostgreSQL 和 Slick 中使用自动递增字段

### 根据数据库表生成 model 类

Django使用数据库表反向生成models类

从 postgresql 数据库中选择值并根据我需要完整查询插入/更新

插入后PostgreSQL触发函数更新