百度申诉网站,博客 wordpress 登录,自适应网站导航怎么做,网站建设开发软件有哪些方面数据库使用的是MySQL#xff0c;JDK版本1.8#xff0c;运行在SpringBoot环境下 本文章源代码#xff1a;https://github.com/runbeyondmove/mybatis-batch-demo 对比3种可用的方式 1、反复执行单条插入语句2、xml拼接sql3、批处理执行 先说结论#xff1a;少量插入请使用反…数据库使用的是MySQLJDK版本1.8运行在SpringBoot环境下 本文章源代码https://github.com/runbeyondmove/mybatis-batch-demo 对比3种可用的方式 1、反复执行单条插入语句2、xml拼接sql3、批处理执行 先说结论少量插入请使用反复插入单条数据方便。数量较多请使用批处理方式。可以考虑以有需求的插入数据量20条左右为界吧在我的测试和数据库环境下耗时都是百毫秒级的方便最重要。无论何时都不用xml拼接sql的方式。 1. xml映射文件中的代码 insert idinsert parameterTypetop.spanrun.bootssm.model.UserInf useGeneratedKeystrue keyPropertyid!--mbggenerated generator自动生成注意order的before和after--!--selectKey keyPropertyid orderAFTER resultTypejava.lang.IntegerSELECT LAST_INSERT_ID()/selectKey--insert into user_inf (id, uname, passwd, gentle, email, city)values (#{id,jdbcTypeINTEGER}, #{uname,jdbcTypeVARCHAR}, #{passwd,jdbcTypeVARCHAR}, #{gentle,jdbcTypeVARCHAR}, #{email,jdbcTypeVARCHAR}, #{city,jdbcTypeVARCHAR})/insertinsert idinsertWithXML parameterTypejava.util.List useGeneratedKeystrue keyPropertyidinsert into user_inf (id, uname, passwd, gentle, email, city)valuesforeach collectionlist itemuser indexindex separator,(#{user.id,jdbcTypeINTEGER}, #{user.uname,jdbcTypeVARCHAR}, #{user.passwd,jdbcTypeVARCHAR},#{user.gentle,jdbcTypeVARCHAR}, #{user.email,jdbcTypeVARCHAR}, #{user.city,jdbcTypeVARCHAR})/foreach/insert2. Mapper接口 Mapper
public interface UserInfMapper {int insert(UserInf record);int insertWithXML(Param(list) ListUserInf list);
}3. Service实现接口声明省略 Service
public class UserInfServiceImpl implements UserInfService{private static final Logger LOGGER LoggerFactory.getLogger(UserInfServiceImpl.class);AutowiredSqlSessionFactory sqlSessionFactory;AutowiredUserInfMapper userInfMapper;TransactionalOverridepublic boolean testInsertWithBatch(ListUserInf list) {LOGGER.info(testInsertWithBatch start);SqlSession sqlSession sqlSessionFactory.openSession(ExecutorType.BATCH,false);UserInfMapper mapper sqlSession.getMapper(UserInfMapper.class);long startTime System.nanoTime();try {ListUserInf userInfs Lists.newArrayList();for (int i 0; i list.size(); i) {// 每1000条提交一次 if ((i1)%1000 0){sqlSession.commit();sqlSession.clearCache();}mapper.insert(list.get(i));}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}LOGGER.info(testInsertWithBatch spend time:{},System.nanoTime()-startTime);LOGGER.info(testInsertWithBatch end);return true;}TransactionalOverridepublic boolean testInsertWithXml(ListUserInf list) {LOGGER.info(testInsertWithXml start);long startTime System.nanoTime();userInfMapper.insertWithXML(list);LOGGER.info(testInsertWithXml spend time:{},System.nanoTime()-startTime);LOGGER.info(testInsertWithXml end);return true;}TransactionalOverridepublic boolean testInsertWithForeach(ListUserInf list) {LOGGER.info(testInsertWithForeach start);long startTime System.nanoTime();for (int i 0; i list.size(); i) {userInfMapper.insert(list.get(i));}LOGGER.info(testInsertWithForeach spend time:{},System.nanoTime()-startTime);LOGGER.info(testInsertWithForeach end);return true;}TransactionalOverridepublic boolean testInsert(UserInf userInf) {LOGGER.info(testInsert start);long startTime System.nanoTime();LOGGER.info(insert before,id userInf.getId());userInfMapper.insert(userInf);LOGGER.info(insert after,id userInf.getId());LOGGER.info(testInsert spend time:{},System.nanoTime()-startTime);LOGGER.info(testInsert end);return true;}
}4. Controller控制器 RestController
public class UserInfController {AutowiredUserInfService userInfService;RequestMapping(value test/{size}/{type})public void testInsert(PathVariable(value size) Integer size,PathVariable(value type) Integer type){System.out.println(type type );switch (type){case 1:userInfService.testInsertWithForeach(generateList(size));break;case 2:userInfService.testInsertWithXml(generateList(size));break;case 3:userInfService.testInsertWithBatch(generateList(size));break;default:UserInf userInf new UserInf();userInf.setUname(user_single);userInf.setGentle(1);userInf.setEmail(123123.com);userInf.setCity(广州市);userInf.setPasswd(123456);userInfService.testInsert(userInf);}}private ListUserInf generateList(int listSize){ListUserInf list Lists.newArrayList();UserInf userInf null;for (int i 0; i listSize; i) {userInf new UserInf();userInf.setUname(user_ i);userInf.setGentle(1);userInf.setEmail(123123.com);userInf.setCity(广州市);userInf.setPasswd(123456);list.add(userInf);}return list;}
}测试结果单位是纳秒 1000
testInsertWithForeach spend time:431526521
testInsertWithXml spend time:118772867
testInsertWithBatch spend time:17560234610000
testInsertWithForeach spend time:2072525050
testInsertWithXml spend time:685605121
testInsertWithBatch spend time:894647254100000
testInsertWithForeach spend time:18950160161
testInsertWithBatch spend time:8469312537testInsertWithXml报错
### Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (9388970 4194304). You can change this value on the server by setting the max_allowed_packet variable.
; Packet for query is too large (9388970 4194304). You can change this value on the server by setting the max_allowed_packet variable.; nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (9388970 4194304). You can change this value on the server by setting the max_allowed_packet variable.] with root causecom.mysql.jdbc.PacketTooBigException: Packet for query is too large (9388970 4194304). You can change this value on the server by setting the max_allowed_packet variable.查看xml sql拼接的异常信息可以发现最大只能达到4194304也就是4M所以这种方式不推荐 结论 循环插入单条数据虽然效率极低但是代码量极少如果在使用tk.Mapper的插件情况下仅需代码, Transactional
public void add1(ListItem itemList) {itemList.forEach(itemMapper::insertSelective);
} 因此在需求插入数据数量不多的情况下肯定用它了。 xml拼接sql是最不推荐的方式使用时有大段的xml和sql语句要写很容易出错工作效率很低。更关键点是虽然效率尚可但是真正需要效率的时候你挂了要你何用 批处理执行是有大数据量插入时推荐的做法使用起来也比较方便。 其他在使用中的补充 1. 使用mybatis generator生成器生成中的一些坑 代码说明数据库是MySQL且主键自增用generator 生成的mapper.xml中的代码自增ID使用的是selectKey来获取。 问题描述insert的时候添加的时候第一条数据添加成功接着添加第二条数据的时候会提示失败失败的原因是ID还是使用的上一个ID值主键重复导致插入失败。异常如下 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 4 for key PRIMARY问题原因BEFORE还是AFTER的问题 selectKey keyPropertyid orderBEFORE resultTypejava.lang.IntegerSELECT LAST_INSERT_ID()
/selectKey需要注意的是Oracle使用beforeMySQL使用after 其实在使用Mybatis generator生成带代码的时候可以通过identitytrue来指定生成的selectKey是before还是after generatedKey columnid sqlStatementMysql identitytrue /注在select标签中使用useGeneratedKeystrue keyPropertyid 不存在该问题。 2. mybatis的版本 升级Mybatis版本到3.3.1 3. 在批量插入的拼接xml sql时注意foreach是没有使用open和close的但是在批量查询修改删除时才使用到open和close foreach collectionlist itemuser indexindex separator,(#{user.id,jdbcTypeINTEGER}, #{user.uname,jdbcTypeVARCHAR}, #{user.passwd,jdbcTypeVARCHAR},#{user.gentle,jdbcTypeVARCHAR}, #{user.email,jdbcTypeVARCHAR}, #{user.city,jdbcTypeVARCHAR})/foreach4. 使用批量提交注意的事项 a. 事务 由于在 Spring 集成的情况下事务连接由 Spring 管理SpringManagedTransaction所以这里不需要手动关闭 sqlSession在这里手动提交commit或者回滚rollback也是无效的。 b. 批量提交 批量提交只能应用于 insert, update, delete。 并且在批量提交使用时如果在操作同一SQL时中间插入了其他数据库操作就会让批量提交方式变成普通的执行方式所以在使用批量提交时要控制好 SQL 执行顺序 转载于:https://www.cnblogs.com/move22/p/9811726.html