Java利用反射机制实现动态生成Sql

场景

编写数据迁移的小工具,需要将大量整理好的对象数据插入不同的表中,按照原有的方式,工作量很大,因此考虑利用反射机制动态 + mybaits 实现动态生成Sql并批量入库

代码

利用 mybatis 注解 @InsertProvider 指定方法生成SQL语句

package com.company.cutover.provider.mapper.jydp;

import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author ryzhang5
 * @Package com.company.cutover.provider.mapper.jydp
 * @date 2020/7/19 17:30
 * @Copyright
 */
public interface InsertDataMapper {
    @InsertProvider(type = DynamicSqlProvider.class, method = "genCreateTableSql")
    Integer insertData(@Param("list") List list, @Param("bean") Class bean);
}

 

package com.company.cutover.provider.mapper.jydp;

import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * @author ryzhang5
 * @Package com.company.cutover.provider.mapper.jydp
 * @date 2020/7/19 16:41
 * @Copyright
 */
public class DynamicSqlProvider {

    /**
     * 生成插入sql
     * @param data
     * @return
     */
    public static String genCreateTableSql(Map data){
        Class bean = (Class) data.get("bean");
        List list = (List) data.get("list");
        String filesList =  getBeanFilesList(bean);
        String valueList = getBeanValueList(bean, list);
        String sql =  "insert into " + getBeanName(bean)+" ("+filesList+") values "+ valueList;
        return sql;
    }

    /**
     * 获取表名
     * @param bean
     * @return
     */
    public static String getBeanName(Class bean){
        try {
            String clzStr = bean.toString();
            //得到类名 (类名即表名)
            String beanName = clzStr.substring(clzStr.lastIndexOf(".")+1);
            return beanName;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 生成字段
     * @param bean
     * @return
     */
    public static String getBeanFilesList(Class bean){
        try {
            Field[] strs = bean.getDeclaredFields();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < strs.length; i++) {
                if (!strs[i].getName().equals("tableName")&&!strs[i].getType().equals("List")) {
                    String str = strs[i].getName().substring(0,1).toUpperCase() + strs[i].getName().substring(1);
                    sb.append("`" + str +"`,");
                }
            }
            sb.deleteCharAt(sb.toString().lastIndexOf(","));
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getBeanValueList(Class bean, List objList){
        StringBuilder sb = new StringBuilder();
        try {
            Field[] tableFields = bean.getDeclaredFields();

            for (Object obj : objList) {
                sb.append("(");
                for (int i = 0; i < tableFields.length; i++) {
                    PropertyDescriptor pd = new PropertyDescriptor(tableFields[i].getName(), bean);
                    Method getMethod = pd.getReadMethod();//获得get方法
                    Object fieldValue = ReflectionUtils.invokeMethod(getMethod, obj);
                    if(fieldValue == null){
                        continue;
                    }
                    if(fieldValue instanceof String){
                        //判断字符串类型是否含有'
                        if(((String) fieldValue).contains("'")){
                            fieldValue = ((String) fieldValue).replaceAll("'","\\\\'");
                        }
                    }
                    sb.append("'" + fieldValue.toString() + "',");
                }
                sb.deleteCharAt(sb.toString().lastIndexOf(","));
                sb.append(")");
                sb.append(",");
            }
            sb.deleteCharAt(sb.toString().lastIndexOf(","));
            return sb.toString();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
 
  

注意

传入的类名、字段名 需同 表明 保持一致

补充:

考虑到大批量数据插入的问题,可以数据分批插入

public void insertData(List list, Class bean){
        //每次数据插入的数量,可做成配置
        int pageSize = 1000;
        int pageIndex = 0;

        while(pageIndex * pageSize < list.size()){
            int startIndex = pageIndex * pageSize;
            int endIndex = (pageIndex + 1) * pageSize;
            endIndex = endIndex > list.size() ? list.size() : endIndex;
            List subList = list.subList(startIndex, endIndex);
            insertDataMapper.insertData(subList, bean);
            try {
                Thread.sleep(1);
            }catch (Exception e){
                e.printStackTrace();
            }
            pageIndex++;
        }
    }

 

你可能感兴趣的:(Java,数据库,mybatis,反射)