建表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for rewrite_sql
-- ----------------------------
DROP TABLE IF EXISTS `rewrite_sql`;
CREATE TABLE `rewrite_sql` (
`id` int NOT NULL DEFAULT -1,
`stu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`age` int NULL DEFAULT -1,
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
搭建项目
server.port=1222
#数据库
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3308/mysql?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#nocas
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#mapper
mybatis.mapper-locations=classpath:mapper/*.xml
#日志输出
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@Data
@TableName("rewrite_sql")
public class RewriteSqlDO implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
private String stuName;
private Integer age;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
}
1、一条条插入
@Test
void test() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for (int i = 10000; i < 20000; i++) { //测试1w条数据耗时
RewriteSqlDO rewriteSqlDO = new RewriteSqlDO();
rewriteSqlDO.setId(i);
rewriteSqlDO.setAge(i);
rewriteSqlDO.setStuName(String.valueOf(1));
rewriteSqlMapper.insert(rewriteSqlDO);
}
stopWatch.stop();
System.out.println(stopWatch.getLastTaskTimeMillis());
}
【注】
优点:
1.spring自带工具类,可直接使用且简单
2.性能消耗小,展示清晰,start和stop之间时间的误差更小
缺点:
一个stopWatch只能开启一个task,必须在stop之后才能开启新的,如果需要开启多个,则需要创建多个stopWatch实例
结果耗时:
2、使用foreach
public interface RewriteSqlMapper extends BaseMapper<RewriteSqlDO> { //注意:这里用的是BaseMapper
int insertBatch(@Param("list") List<RewriteSqlDO> list);
}
<insert id="insertBatch" parameterType="java.util.List">
insert into rewrite_sql(id, stu_name, age, create_time) values
<foreach collection="list" item="item" separator=",">
(#{item.id}, #{item.stuName}, #{item.age}, #{item.createTime})
</foreach>
</insert>
在配置文件数据库配置中加入:&rewriteBatchedStatements=true
@Test
void test1() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
List<RewriteSqlDO> rewriteSqlDOList = new ArrayList<RewriteSqlDO>();
for (int i = 1; i < 10000; i++) {
RewriteSqlDO rewriteSqlDO = new RewriteSqlDO();
rewriteSqlDO.setId(i);
rewriteSqlDO.setAge(i);
rewriteSqlDO.setStuName(String.valueOf(i));
rewriteSqlDOList.add(rewriteSqlDO);
}
rewriteSqlMapper.insertBatch(rewriteSqlDOList);
stopWatch.stop();
System.out.println(stopWatch.getLastTaskTimeMillis());
}
结果耗时:
3、自定义插入/更新
简述就是,封装好的foreach方法,性能耗时与第二种接近
public interface CommonMapper<T> extends BaseMapper<T> {
/**
* 自定义批量插入
* 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
*/
int insertBatch(@Param("list") List<T> list);
/**
* 自定义批量更新,条件为主键
* 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
*/
int updateBatch(@Param("list") List<T> list);
}
/**
* 批量新增
*/
@Slf4j
public class InsertBatchMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s</script>";
final String fieldSql = prepareFieldSql(tableInfo);
final String valueSql = prepareValuesSql(tableInfo);
final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
log.debug("sqlResult----->{}", sqlResult);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
// 第三个参数必须和RootMapper的自定义方法名一致
return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);
}
private String prepareFieldSql(TableInfo tableInfo) {
StringBuilder fieldSql = new StringBuilder();
fieldSql.append(tableInfo.getKeyColumn()).append(",");
tableInfo.getFieldList().forEach(x -> {
//新增时修改字段不填充
if (!("update_time".equals(x.getColumn()))
&&!("update_user_id".equals(x.getColumn()))
&&!("update_user_name".equals(x.getColumn()))){
fieldSql.append(x.getColumn()).append(",");
}
});
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
return fieldSql.toString();
}
private String prepareValuesSql(TableInfo tableInfo) {
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
tableInfo.getFieldList().forEach(x -> {
if (!("updateTime".equals(x.getProperty()))
&&!("updateUserId".equals(x.getProperty()))
&&!("updateUserName".equals(x.getProperty()))){
valueSql.append("#{item.").append(x.getProperty()).append("},");
}
});
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
return valueSql.toString();
}
}
/**
* 批量更新方法实现,条件为主键,选择性更新
*/
@Slf4j
public class UpdateBatchMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "<script>\n<foreach collection=\"list\" item=\"item\" separator=\";\">\nupdate %s %s where %s=#{%s} %s\n</foreach>\n</script>";
String additional = tableInfo.isWithVersion() ? tableInfo.getVersionFieldInfo().getVersionOli("item", "item.") : "" + tableInfo.getLogicDeleteSql(true, true);
String setSql = sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, "item", "item.");
String sqlResult = String.format(sql, tableInfo.getTableName(), setSql, tableInfo.getKeyColumn(), "item." + tableInfo.getKeyProperty(), additional);
log.debug("sqlResult----->{}", sqlResult);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
// 第三个参数必须和RootMapper的自定义方法名一致
return this.addUpdateMappedStatement(mapperClass, modelClass, "updateBatch", sqlSource);
}
}
@Slf4j
public class MyInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
// log.info("==============methodList===================");
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new InsertBatchMethod());
methodList.add(new UpdateBatchMethod());
return methodList;
}
}
@Slf4j
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
// log.info("===================mybatisPlusInterceptor====================");
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
@Bean
public MyInjector myInjector(){
// log.info("========================myInjector===================================");
return new MyInjector();
}
}
@Test
void test2() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
List<RewriteSqlDO> rewriteSqlDOList = new ArrayList<RewriteSqlDO>();
for (int i = 100000; i < 200000; i++) {
RewriteSqlDO rewriteSqlDO = new RewriteSqlDO();
rewriteSqlDO.setId(i);
rewriteSqlDO.setAge(i);
rewriteSqlDO.setStuName(String.valueOf(i));
rewriteSqlDOList.add(rewriteSqlDO);
}
rewriteSqlMapper.insertBatch(rewriteSqlDOList);
stopWatch.stop();
System.out.println(stopWatch.getLastTaskTimeMillis());
}
【注意】
在配置文件数据库配置中加入:&allowMultiQueries=true
结果耗时:
标签:tableInfo,String,批量,rewriteSqlDO,stopWatch,plus,mybatis,new,append From: https://www.cnblogs.com/shirleyxueli/p/17448142.html