数据库开发过程中经常会遇到需要批量插入数据的问题,比如:需要对一个文件执行解析入库的操作;
本文以Mybatis的foreach为例,(假定Mybatis环境已经配置好)向MySQL中批量插入数据;
方法一:
1. dao中设置要插入的数据;
public int insertRecordsFromList(List<LoginLog> list){
Map<String, List<LoginLog> > map = new HashMap<String, List<LoginLog> >();
map.put("loginlogs", list);
int num =
sqlSessionTemplate.insert(LOGIN_LOG_NAMESPACE + "insertRecordsFromList", map);
return num;
}
其中list中为待插入的数据,接下来将list放到map中去(之所以这样做,是因为我刚开始是直接传list,会报错);
2.sqlmap里面如下:
<select id="insertRecordsFromList" parameterType="java.util.Map">
insert into t_login_log (login_log_id, user_id, ip,login_datetime) values
<foreach collection="loginlogs" item="item" index="index" separator=",">
(#{item.loginLogId,jdbcType=DECIMAL},
#{item.userId,jdbcType=DECIMAL},
#{item.ip,jdbcType=VARCHAR},
#{item.loginDatetile,jdbcType=VARCHAR})
</foreach>
</select>
collection的值即为dao中设置的map的key;分隔符用“,”,组成类似如下的sql:
insert into table_name (col1, col2) values
(val1, val2),
(val11,val22);
如此即可实现向数据库中批量插入数据了;
方法二:
对于方法一,如果数据量比较大的情况,数据解析入库的数据会很慢,计算资源主要消耗在MyBatis解析foreach里面的参数里了,这里提供另外一种方法,避免MyBatis频繁解析参数给程序带来的性能消耗;
方法很简单,即在java代码中把要插入的数据拼接成字符串,例如方法一中提到的SQL语句 insert into table_name(col1,col2)values(val1, val2),
(val11,val22); 拼接的字符串如下 “(val1,val2),(val11,val22)”。SqlMap里如下:
<select id="batchInsert" parameterType="java.util.Map">
insert into t_login_log (login_log_id, user_id, ip,login_datetime) values
${details}<!--此处为拼接sql,用"$",而不用"#",用"#"会在参数上自动加上双引号,在此处会报错误,其中details为拼接的记录 -->
</select>
即把要插入的记录拼接成一个字符串,MyBatis只解析这一个字符串。这种方式在数据量比较大的情况下,相比于方法一,效率有很大的提升;
不过这个方法会带来另外一个问题:由于使用“$”进行直接拼接SQL语句,会有SQL注入的风险,所以具体项目中采用哪种方式,还需要自己权衡。