海量数据的插入
首选Jdbc批量处理,其次就是自己拼接好完整的SQL语句,交给Jdbc处理
Jdbc批处理
伪代码
- 创建SQL语句
- 从数据库连接池中获取数据库连接
- 绑定SQL语句
- 取消自动提交
- 创建需要插入的数据
- 将语句添加到模板中
- 执行模板
- 清空模板
- 提交事务
- 关闭连接
真代码
@Slf4j
public class BatchInsertData {
//注入数据库连接池,我这里采用的是Druid连接池
@Autowired
private DruidDataSource dataSource;
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void insertData(){
//记录开始时间:
log.info("start:" + LocalDate.now())
//注意在构建SQL语句时不要在最后面添加分号(;)
String sql = "INSERT INTO personnel_info(gender,`name`,`institution_id`) VALUES (?,?,?)";
DruidPooledConnection connection = null;
PreparedStatement ps = null;
try {
//从数据库连接池中获取数据库连接
connection = dataSource.getConnection();
//绑定SQL语句
ps = connection.prepareStatement(sql);
//取消自动提交事务
connection.setAutoCommit(false);
//构建数据
for (int j = 0; j < 200000; j++) {
for (int k = 1; k <= 10; k++) {
//设置性别
if(k % 2 == 0)
ps.setInt(1,0);
else
ps.setInt(1,1);
ps.setString(2,"人员" + k);
ps.setInt(3,j);
//构建好一条数据就添加到模板中
ps.addBatch();
}
}
//执行模板
ps.executeBatch();
//清空模板
ps.clearBatch();
//提交事务
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
//关闭连接,释放连接
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//记录结束时间:
log.info("end:" + LocalDate.now())
}
}
完整SQL语句执行
主要是拼接SQL语句,这里注意最好不要用String去凭借,大量的数据进拼接可能会带来多余的内存消耗,所以我这里采用StringBiuder去做拼接
伪代码
- 创建基础SQL语句
- 进行Values后面内容的拼接
- 拼接完成后一次性执行完整的SQL语句
真代码
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void generateData(){
//设置开始时间
log.info("start:" + LocalDate.now());
//构建基础SQL
StringBuilder sql = new StringBuilder("INSERT INTO personnel_info(gender,`name`,`institution_id`) VALUES ");
//构建内容,并进行拼接
for (int i = 0; i < 100000; i++) {
for (int j = 1; j <= 10; j++) {
StringBuilder values = new StringBuilder("(");
//设置性别
if(i % 2 == 0)
values.append("0,");
else
values.append("1,");
//设置姓名
values.append("'人员").append(j).append("',");
//设置机构Id
values.append(i).append(")");
sql.append(values);
if (i < start + 59999){
sql.append(",");
} else if (i == start + 59999) {
if(j < 10){
sql.append(",");
}else {
sql.append(";");
}
}
}
}
//拼接完成,执行SQL语句
jdbcTemplate.batchUpdate(sql.toString());
log.info("end:" + LocalDate.now());
}
注意在使用批量插入时,需要在配置文件中的数据库配置地方,数据库url地址后面加上设置允许批处理
&rewriteBatchedStatements=true
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/dataBase?useUnicode=true&characterEncoding=utf-8&useSSL=false&rewriteBatchedStatements=true
username: username
password: passsword
# 连接池配置
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
如果数据量特别大,可以采用分批次提交,设置一定的插入数据量,再给批量插入方法设置一个定时job,让系统隔一段时间就插入一定量的数据,这样可以解开双手,也可以避免一次性插入海量数据带来的内存压力