目录
mapper介绍:
InsertListMapper.insertList 有值没值的字段都会插入!
手写 batchInsert方法,配置xml,插入自定义主键
insertSelective(obj) 主键无要求
insert(obj) 主键无要求
https://gitee.com/importer/Mapper/
先说结论:少量插入请使用反复插入单条数据,方便。数量较多请使用批处理方式。(一次性插20~50行数量是比较合适的)。
其中sql的values 拼接方式在插入5000左右时报错(似乎是因为sql语句过长)。不过数据量大的时候,比如2000条数据,可以拆成多个list批量插入。总结一下,如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用
而实际上,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 extends T> 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 ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , (
?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , (
?,?,?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,?,?,? ) , (
?,?,?,?,?,?,?,?,?,?,?,?,? )
//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);
//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) 只会插入有值的字段,同时一条数据一次插入
//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) 区别!同时一条数据一次插入