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<String, Object> data){
        Class bean = (Class) data.get("bean");
        List<Object> list = (List<Object>) 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<Object> 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++;
        }
    }

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java通过反射注解生成对应的SQL语句的步骤如下: 1. 定义注解:首先需要定义一个注解,该注解用于标识字段信息,例如字段名、字段类型、是否为主键等信息。 ``` @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String name(); // 字段名 String type(); // 字段类型 boolean primaryKey() default false; // 是否为主键 } ``` 2. 定义实体类:在实体类的字段上使用上面定义的注解。 ``` public class User { @Column(name = "id", type = "int", primaryKey = true) private int id; @Column(name = "name", type = "varchar") private String name; @Column(name = "age", type = "int") private int age; // 省略getter和setter方法 } ``` 3. 通过反射获取实体类的字段信息:通过反射获取实体类的字段信息,然后读取字段上的注解,获取字段名、字段类型和是否为主键等信息。 ``` public static <T> String generateCreateTableSql(Class<T> clazz) { StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE IF NOT EXISTS "); sb.append(clazz.getSimpleName()); sb.append("("); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); sb.append(column.name()); sb.append(" "); sb.append(column.type()); if (column.primaryKey()) { sb.append(" PRIMARY KEY"); } sb.append(","); } } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } ``` 4. 生成SQL语句:将读取到的字段信息拼接成对应的SQL语句,例如创建表、插入数据、更新数据等。 ``` public static <T> String generateInsertSql(T entity) { StringBuilder sb = new StringBuilder(); sb.append("INSERT INTO "); sb.append(entity.getClass().getSimpleName()); sb.append("("); Field[] fields = entity.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); sb.append(column.name()); sb.append(","); } } sb.deleteCharAt(sb.length() - 1); sb.append(") VALUES ("); for (Field field : fields) { if (field.isAnnotationPresent(Column.class)) { field.setAccessible(true); Object value = field.get(entity); if (value instanceof String) { sb.append("'"); sb.append(value); sb.append("'"); } else { sb.append(value); } sb.append(","); } } sb.deleteCharAt(sb.length() - 1); sb.append(")"); return sb.toString(); } ``` 以上就是利用反射注解生成对应的SQL语句的步骤,可以根据需要进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值