tk.mybatis之插入(主键自增)、批量插入笔记insertList、batchInsert、insertSelective、insert

目录

 

 

mapper介绍:

InsertListMapper.insertList   有值没值的字段都会插入!

手写 batchInsert方法,配置xml,插入自定义主键

 insertSelective(obj)      主键无要求

 insert(obj)     主键无要求


 

mapper介绍:

https://gitee.com/importer/Mapper/

 

先说结论:少量插入请使用反复插入单条数据,方便。数量较多请使用批处理方式。(一次性插20~50行数量是比较合适的)。

其中sql的values 拼接方式在插入5000左右时报错(似乎是因为sql语句过长)。不过数据量大的时候,比如2000条数据,可以拆成多个list批量插入。总结一下,如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用 的插入的话,需要将每次插入的记录控制在 20~50 左右。

 

而实际上,MyBatis文档中写批量插入的时候,是推荐使用另外一种方法。即基本思想是将 MyBatis session 的 executor type 设为 Batch ,然后多次执行插入语句。就类似于JDBC的下面语句一样。

参考:https://blog.csdn.net/huanghanqian/article/details/83177178

 

描述:

//传统单条插入
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");


//sql拼接
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"),
                                                 ("data1", "data2"),
                                                 ("data1", "data2"),
                                                 ("data1", "data2"),
                                                 ("data1", "data2");

 

1、sql拼接方式插入:

InsertListMapper.insertList   有值没值的字段都会插入!

条件限制实体包含`id`属性并且必须为自增列

/**
     * 批量插入,支持批量插入的数据库可以使用,例如MySQL,H2等,另外该接口限制实体包含`id`属性并且必须为自增列
     *
     * @param recordList
     * @return
     */
    @Options(useGeneratedKeys = true)
    @InsertProvider(type = SpecialProvider.class, method = "dynamicSQL")
    int insertList(List recordList);

 

否则报错:


org.springframework.dao.DataIntegrityViolationException: 
### Error updating database.  Cause: java.sql.SQLException: Field 'stream_box_id' doesn't have a default value
### The error may involve com.hierway.vslm.dataaccess.mybatis.mapper.StreamBoxDao.insertList-Inline
### The error occurred while setting parameters

 

接口的实现类源码:

public class SpecialProvider extends MapperTemplate {

    public SpecialProvider(Class mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    /**
     * 批量插入
     *
     * @param ms
     */
    public String insertList(MappedStatement ms) {
        final Class entityClass = getEntityClass(ms);
        //开始拼sql
        StringBuilder sql = new StringBuilder();
        sql.append("");
        sql.append(SqlHelper.insertIntoTable(entityClass, tableName(entityClass), "list[0]"));
        sql.append(SqlHelper.insertColumns(entityClass, true, false, false));
        sql.append(" VALUES ");
        sql.append("");
        sql.append("");
        //获取全部列
        Set columnList = EntityHelper.getColumns(entityClass);
        //当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值
        for (EntityColumn column : columnList) {
            if (!column.isId() && column.isInsertable()) {
                sql.append(column.getColumnHolder("record") + ",");
            }
        }
        sql.append("");
        sql.append("");

        // 反射把MappedStatement中的设置主键名
        EntityHelper.setKeyProperties(EntityHelper.getPKColumns(entityClass), ms);

        return sql.toString();
    }

    /**
     * 插入,主键id,自增
     *
     * @param ms
     */
    public String insertUseGeneratedKeys(MappedStatement ms) {
        final Class entityClass = getEntityClass(ms);
        //开始拼sql
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.insertIntoTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.insertColumns(entityClass, true, false, false));
        sql.append(SqlHelper.insertValuesColumns(entityClass, true, false, false));

        // 反射把MappedStatement中的设置主键名
        EntityHelper.setKeyProperties(EntityHelper.getPKColumns(entityClass), ms);

        return sql.toString();
    }
}

参考:https://blog.csdn.net/donkeyboy001/article/details/86903969

 

sql拼接语句:

==>  Preparing: INSERT INTO stream_box ( 
stream_line_id,start_time,end_time,capability,use_state,op_state,set_id,req_id,spec_id,p
re_set_id,pre_use_capability,last_set_id,last_use_capability ) 
  VALUES ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( 
?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( 
?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( 
?,?,?,?,?,?,?,?,?,?,?,?,? ) 

 

 

手写 batchInsert方法,配置xml,插入自定义主键

//dao接口
int batchInsert(@Param("list") List list);

XML配置

 
    
        INSERT INTO stream_box (stream_box_id,xxx,xxx,xxx,xxx,xxx,xxx,xxx)
        VALUES
        
            (
            #{item.streamBoxId},#{item.xxx},#{item.xxx},#{item.xxx},#{item.xxx},#{item.xxx},#{item.xxx},
            #{item.xxx}
            )
        
    

另一种实现可参考:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
    SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class);
    List records = getRecordsToInsert(); // not shown
 
    BatchInsert batchInsert = insert(records)
            .into(simpleTable)
            .map(id).toProperty("id")
            .map(firstName).toProperty("firstName")
            .map(lastName).toProperty("lastName")
            .map(birthDate).toProperty("birthDate")
            .map(employed).toProperty("employed")
            .map(occupation).toProperty("occupation")
            .build()
            .render(RenderingStrategy.MYBATIS3);
 
    batchInsert.insertStatements().stream().forEach(mapper::insert);
 
    session.commit();
} finally {
    session.close();
}

将 MyBatis session 的 executor type 设为 Batch ,然后多次执行插入语句。

Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root");
connection.setAutoCommit(false);
PreparedStatement ps = connection.prepareStatement(
        "insert into tb_user (name) values(?)");
for (int i = 0; i < stuNum; i++) {
    ps.setString(1,name);
    ps.addBatch();
}
ps.executeBatch();
connection.commit();
connection.close();

 

 

 

 

 

2、循环插入单条数据

//方法1、执行对应的sql语句的时候,只插入对象 有值 的字段,没有值的字段不加入sql里
 insertSelective(obj);

//方法2、每个字段都要添加一遍
 insert(obj);

 

 insertSelective(obj)      主键无要求

//sBoxes 有四条数据
List sBoxes = getSboxes("insertSelectiveTKMybatis");

//insertSelective执行对应的sql语句的时候,只插入对应的name字段
sBoxes.forEach(sBox -> streamBoxDao.insertSelective(sBox) );

看输出的sql日志

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31ecb361] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4cc4f6bd] will not be managed by Spring
==>  Preparing: INSERT INTO stream_box ( stream_box_id,stream_line_id,start_time,end_time,capability,use_state,op_state,spec_id ) VALUES( ?,?,?,?,?,?,?,? ) 
==> Parameters: sboxinsertSelectiveTKMybatis1(String), slineid1(String), 2020-03-24 10:00:00.0(Timestamp), 2020-03-24 10:00:00.0(Timestamp), 100.0(Double), 0(Byte), 1(Byte), spec1(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@31ecb361]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7896e96a] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@4cc4f6bd] will not be managed by Spring
==>  Preparing: INSERT INTO stream_box ( stream_box_id,stream_line_id,start_time,end_time,capability,use_state,op_state,spec_id ) VALUES( ?,?,?,?,?,?,?,? ) 
==> Parameters: sboxinsertSelectiveTKMybatis2(String), slineid2(String), 2020-03-24 04:00:00.0(Timestamp), 2020-03-24 04:00:00.0(Timestamp), 200.0(Double), 0(Byte), 1(Byte), spec2(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7896e96a]
Creating a new SqlSession
...
Creating a new SqlSession
...

 

看控制台输出得出结论: insertSelective(obj)  只会插入有值的字段,同时一条数据一次插入

 

 

 

 insert(obj)     主键无要求

//sBoxes 有四条数据
List sBoxes = getSboxes("insertTKMybatis");

//insertSelective执行对应的sql语句的时候,只插入对应的name字段
sBoxes.forEach(sBox -> streamBoxDao.insert(sBox) );

控制台输出

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7fda84cf] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@58922a00] will not be managed by Spring
==>  Preparing: INSERT INTO stream_box ( stream_box_id,stream_line_id,start_time,end_time,capability,use_state,op_state,set_id,req_id,spec_id,pre_set_id,pre_use_capability,last_set_id,last_use_capability ) VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,?,? ) 
==> Parameters: sboxinsertTKMybatis1(String), slineid1(String), 2020-03-24 02:00:00.0(Timestamp), 2020-03-24 02:00:00.0(Timestamp), 100.0(Double), 0(Byte), 1(Byte), null, null, spec1(String), null, null, null, null
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7fda84cf]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@765e5a55] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@58922a00] will not be managed by Spring
==>  Preparing: INSERT INTO stream_box ( stream_box_id,stream_line_id,start_time,end_time,capability,use_state,op_state,set_id,req_id,spec_id,pre_set_id,pre_use_capability,last_set_id,last_use_capability ) VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,?,? ) 
==> Parameters: sboxinsertTKMybatis2(String), slineid2(String), 2020-03-24 06:00:00.0(Timestamp), 2020-03-24 06:00:00.0(Timestamp), 200.0(Double), 0(Byte), 1(Byte), null, null, spec2(String), null, null, null, null
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@765e5a55]
Creating a new SqlSession
...
Creating a new SqlSession
...

看控制台输出得出结论: insert(obj)  有值没值的字段都会插入!

这是和上面的insertSelective(obj)  区别!同时一条数据一次插入

 

 

 

 

 

你可能感兴趣的:(mybatis,mysql学习)