实时批量推送数据 亿级数据插入

1. 场景:

通过Jmeter 调用接口 将数据 添加到队列中然后, 再消费队列, 批量插入数据库
在这里插入图片描述

2. 代码

项目结构

在这里插入图片描述

类:ApplicationQueue

package com.wudl.queue.config;


import com.wudl.queue.domain.User;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 22:08
 * @description:
 * @modified By:
 * @version: 1.0
 */

public class ApplicationQueue {
    //队列大小
    static final int QUEUE_MAX_SIZE = 1000;

    static BlockingQueue<User> blockingQueue = new LinkedBlockingQueue<User>(Integer.MAX_VALUE);

    /**
     * 私有的默认构造子,保证外界无法直接实例化
     */
    private ApplicationQueue() {
    }

    ;

    /**
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
     */
    private static class SingletonHolder {
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private static ApplicationQueue queue = new ApplicationQueue();
    }

    //单例队列
    public static ApplicationQueue getMailQueue() {
        return SingletonHolder.queue;
    }

    //生产入队
    public void produce(User mail) throws InterruptedException {
        blockingQueue.put(mail);
    }

    //消费出队
    public User consume() throws InterruptedException {
        return blockingQueue.take();
    }

    // 获取队列大小
    public int size() {
        return blockingQueue.size();
    }
}

线程MyAppThreadFactory

package com.wudl.queue.config;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 22:49
 * @description:
 * @modified By:
 * @version: 1.0
 */

public class MyAppThreadFactory {
    /**
     * 线程池执行器 Executors 首选的线程池
     * ExecutorService executorService=Executors.newCachedThreadPool();
     */
    public static ExecutorService myCachedThreadPool= new ThreadPoolExecutor(0, Integer.MAX_VALUE,
            60L, TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>());
}

消费者

package com.wudl.queue.config;

import com.wudl.queue.domain.User;
import com.wudl.queue.service.UserService;
import lombok.Synchronized;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 22:26
 * @description:
 * @modified By:
 * @version: 1.0
 */

@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
@Component
public class UserConsume  {

    @Autowired
    UserService userService;

    List<User> list = new LinkedList<>();
    int number = 0;
    public synchronized   void run() throws Exception {


        while (true) {
            User consume = null;
            try {
                consume = ApplicationQueue.getMailQueue().consume();

                FileWriter fw = new FileWriter("D:\\tmp\\CCCC.txt", true);
                BufferedWriter bw = new BufferedWriter(fw);

                bw.append("消费-->");
                bw.write(consume.toString() + "\r\n ");
                bw.close();
                fw.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        list.add(consume);
        if (list.size() >=10)
        {

            List<User> strsSync = Collections.synchronizedList(list);


            userService.insertBatch(strsSync);
            System.out.println(list.size());
            list.clear();
        }
        }
    }

    private static String lock = "";
    @Synchronized
    @Scheduled(fixedDelay = 100)  //间隔1秒
    public void cleanRankListJobExecute() throws Exception {

        User  consume = ApplicationQueue.getMailQueue().consume();

        MyAppThreadFactory.myCachedThreadPool.execute(()->
        {

        });
        try {
            synchronized (lock){
                run();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

接口

package com.wudl.queue.controller;

import com.wudl.queue.domain.User;
import com.wudl.queue.service.UserService;
import com.wudl.queue.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 20:49
 * @description:控制层
 * @modified By:
 * @version: 1.0
 */

@RestController
public class UserController {

//    @Autowired
//    Producer  producer;

    private static String lock = "";
    @Autowired
    UserService userService;
    int i = 0;



    @GetMapping("/user/findall")
    public List<User> findall() throws Exception {


        List<User> all = userService.findAll();

        return all;


    }

    @GetMapping("/user/addUser")
    public String addUser() throws Exception {

        User u = new User();
        u.setId(9);
        u.setUserNo("100014");
        u.setUserName("myhdfs");

        userService.addUser(u);

        return "success";


    }

    @GetMapping("/user/insertBatch")
    public String insertBatch() throws Exception {
        i++;

        User u = new User();
        u.setId(9);
        u.setUserNo("100014"+i);
        u.setUserName("myFlink"+i);
        userService.insertBatchTow(u);
            FileWriter fw = new FileWriter("D:\\tmp\\x.txt", true);
            BufferedWriter bw = new BufferedWriter(fw);

            bw.append("消费-->"+i);
            bw.write(u.toString() + "\r\n ");
            bw.close();
            fw.close();
        return "success";


    }
}

实体类

package com.wudl.queue.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author :wudl
 * @date :Created in 2021-12-22 22:50
 * @description:
 * @modified By:
 * @version: 1.0
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Integer id;
    private String userName;
    private String userNo;
}

持久层

package com.wudl.queue.mapper;

import com.wudl.queue.domain.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @author :wudl
 * @date :Created in 2021-12-22 22:51
 * @description:
 * @modified By:
 * @version: 1.0
 */
@Mapper
public interface UserMapper
{

     /**
      * 查询所有
      * @return
      */
     List<User> findAll();

     void addUser(User user);

    void  insertBatch(List<User> list);

}

接口实现

package com.wudl.queue.service.impl;

import com.wudl.queue.config.ApplicationQueue;
import com.wudl.queue.domain.User;
import com.wudl.queue.mapper.UserMapper;
import com.wudl.queue.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 22:12
 * @description:
 * @modified By:
 * @version: 1.0
 */

@Service
public class UserServiceImpl implements UserService {


    @Autowired
    UserMapper userMapper;

//    @Override
//    public void sendQueue(User user) throws Exception {
//        MailQueue.getMailQueue().produce(user);
//
//    }

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    public void addUser(User user) {
        userMapper.addUser(user);
    }

    @Override
    public void insertBatch(List<User> list) {

        userMapper.insertBatch(list);
    }

    @Override
    public void insertBatchTow(User list) throws InterruptedException {

        ApplicationQueue.getMailQueue().produce(list);
//        userMapper.insertBatch(list);
    }


}

接口

package com.wudl.queue.service;


import com.wudl.queue.domain.User;

import java.util.List;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 22:11
 * @description:
 * @modified By:
 * @version: 1.0
 */

public interface UserService {
//    public void sendQueue(User user) throws Exception;


    public List<User>  findAll();

    void addUser(User user);
    void insertBatch(List<User> list);
    void insertBatchTow(User list) throws InterruptedException;


}

package com.wudl.queue.utils;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author :wudl
 * @date :Created in 2021-12-12 21:47
 * @description:
 * @modified By:
 * @version: 1.0
 */

public class BlockingQueueMessage {
    public static BlockingQueue<String> queue = new LinkedBlockingQueue<>(5);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wudl.queue.mapper.UserMapper">
    <select id="findAll" resultType="com.wudl.queue.domain.User">
        select * from user
    </select>

    <insert id="addUser" parameterType="com.wudl.queue.domain.User">

        INSERT INTO user (id,userNo,userName) VALUE(#{id},#{userNo},#{userName})
    </insert>

    <!-- 批量插入 -->
    <insert id ="insertBatch" parameterType="java.util.List" >

        insert into user
        (userNo,userName)
        values
        <foreach collection ="list" item="u" index= "index" separator =",">
            (
             #{u.userNo},
            #{u.userName}
            )
        </foreach >
    </insert >
</mapper>
spring:
  datasource:
    #数据源基本配置
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.1.180:3306/test?serverTimezone=UTC
    type: com.alibaba.druid.pool.DruidDataSource
  #数据源其他配置
  druid:
    #配置初始化大小、最小、最大线程数
    initialSize: 5
    minIdle: 5
    #CPU核数+1,也可以大些但不要超过20,数据库加锁时连接过多性能下降
    maxActive: 20
    #最大等待时间,内网:800,外网:1200(三次握手1s)
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    #配置一个连接在池中最大空间时间,单位是毫秒
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1
    testWhileIdle: true
    #设置从连接池获取连接时是否检查连接有效性,true检查,false不检查
    testOnBorrow: true
    #设置从连接池归还连接时是否检查连接有效性,true检查,false不检查
    testOnReturn: true
    #可以支持PSCache(提升写入、查询效率)
    poolPreparedStatements: true
    #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,log4j
    #保持长连接
    keepAlive: true
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500


#整合mybatis
mybatis:
  #配置别名
  type-aliases-package: com.wudl.queue.domain
  #配置 xml 文件映射  classpath: = resources   /=当前项目下
  mapper-locations: classpath:mapper/*.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>wudl-LinkedBlockingQueue</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter</artifactId>-->
<!--        </dependency>-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>
</project>

插入结果:100万数据 一条没有丢

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值