(一)mybatis实现对象的批量插入(可以指定任意类,任意表,任意属性进行插入)

mybatis实现对象的批量插入,先写一个批量查询的sql::

Insert into t_table (column1,column2) values (attribute1,attribute2),(attribute3,attribute4);

其中t_table是表名,column1,column2是表列属性,attribute1,attribute2这些则是要插入的字段。

为了实现任意表中的任意属性插入,需要把t_table,column1,column2,以及attribute1,attribute2以参数的形式从java代码中代入数据库,怎么代入呢?

我们可以通过自定义注解方式处理:

package com.bo.annotate;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DbColumn {
    /**
     * 表列名称
     * @return
     */
     String name() default "";

    /**
     * 是否确认修改
     */
    //这个是做批量修改用的,暂时不需要用到
    boolean canModify() default false;

}

 @DbColumn定义的是属性上使用的注解,其中name指的是表列的列名,在插入数据库中需要明确插入哪些列。

package com.bo.annotate;

import java.lang.annotation.*;

/**
 * 此注解操作数据库
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DbTable {
    String name() default "";
}

@DbTable这个注解在类上方使用,表示这个类对应的表名,其中name属性指的就是表名。

数据库表结构如下:

CREATE TABLE `t_teacher` (
  `f_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `f_name` varchar(255) DEFAULT NULL COMMENT '教师姓名',
  `f_age` bigint(20) DEFAULT NULL COMMENT '学生年龄',
  `f_subject` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`f_id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8
 

接下来在我们的pojo实体类上打注解,如下:

package com.bo.pojo;

import com.bo.annotate.DbColumn;
import com.bo.annotate.DbTable;

@DbTable(name = "t_teacher")
public class Teacher {

    /**
     * 姓名
     */
    @DbColumn(name = "f_name",canModify = false)
    private String name;

    /**
     * 年龄
     */
    @DbColumn(name = "f_age",canModify = false)
    private Integer age;

    /**
     * 性别
     */
    @DbColumn(name = "f_subject",canModify = false)
    private String subject;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }
}

其中,数据库表的名称是t_teacher, 而f_name,f_age这些都是表中对应的列名,我们可以通过自定义注解来获取到要插入的表名与表中属性。

接下来就是编写插入操作的方法了:

 public void batchInstert(List<T> list) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        if(CollectionUtils.isEmpty(list)){
            throw new RuntimeException("批量添加集合不能为空");
        }
        T t = list.get(0);
        Class<?> aclass = t.getClass();
        boolean annotationPresent = aclass.isAnnotationPresent(DbTable.class);

        if(annotationPresent == false){
            throw new RuntimeException("批量添加未获取数据库注解");
        }
        DbTable dbTable = aclass.getAnnotation(DbTable.class);
        List<String> columns = new ArrayList<>();
        List<String> attributes = new ArrayList<>();
        Field[] fields = aclass.getDeclaredFields();
        for(Field field:fields){
            boolean annotationPresentField = field.isAnnotationPresent(DbColumn.class);
            if(annotationPresentField == true){
                //获取当前数据库属性名称
                DbColumn dbColumn = field.getAnnotation(DbColumn.class);
                columns.add(dbColumn.name());
                //获取当前类属性名称
                String name = field.getName();
                attributes.add(name);

            }
        }
        //获取到标注批量添加属性的级别
        String tableName = dbTable.name();

        //TODO 问题应该出现在属性的注入顺序上以及mybatis遍历map上
       List<Map<String, Object>> mapList = new ArrayList<>();
        for(T obj:list){
            Map<String, Object> map = new LinkedHashMap<>();
            StringBuilder builder = new StringBuilder();
            for(String attribute:attributes){
                String attFirst = attribute.substring(0, 1).toUpperCase();
                String attLast = attribute.substring(1, attribute.length());

                String getter = builder.append("get").
                        append(attFirst).append(attLast).toString();
                Method method = obj.getClass().getMethod(getter,null);
                Object invoke = method.invoke(obj, null);
                map.put(attribute, invoke);
                builder.setLength(0);
            }
            mapList.add(map);

        }
        logger.info("tableName:"+tableName);
        dataBaseUtilsMapper.batchInsert(tableName,columns,mapList);
    }

batchInsert的sql是这么写的:

<insert id="batchInsert">
        insert into ${tableName}
        <foreach collection="columns" index="index" separator="," open="(" close=")" item="item">
            ${item}
        </foreach>
        values
        <foreach collection="mapList" index="index" separator="," item="map">
            <foreach collection="map" index="key" separator="," open="(" close=")" item="attribute">
                #{attribute}
            </foreach>
        </foreach>;
    </insert>

先声明一下为何tableName,item要用${}接收,经过楼主的亲身体验,如果用#{}来进行传递的话,那么字符串会带上“ ”,sql执行过程中表名肯定是没有“ ”的,所以用${}来接收。

写个测试类:

@Test
    public void test01() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        List<Teacher> teachers = new ArrayList<>();
        Teacher teacher = new Teacher();
        teacher.setName("嘉德");
        teacher.setAge(22);
        teacher.setSubject("计算机");
        Teacher teacher1 = new Teacher();
        teacher1.setName("月色");
        teacher1.setAge(21);
        teacher1.setSubject("IT");
        teachers.add(teacher);
        teachers.add(teacher1);
       /* log.warn(teacher.getName());*/
        utils.batchInstert(teachers);
    }

执行后的结果:

这样一个批量添加就完成了,楼主亲写亲测,可用,希望能帮助大家,也希望大家能指出不足,新手上路,多多关照。

猜你喜欢

转载自blog.csdn.net/key_wu/article/details/88085890