基于mybatisplus 的 java 异步储存队列
异步储存,减少与数据库之间的交互造成的堵塞使性能下降
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.LinkedList;
import java.util.List;
/**
* ClassName: MybatisSaveMQ
* Description: 保存队列
* date: 2021-03-19
*
* @since JDK 1.8
*/
public class MybatisSaveMQ<T> {
private volatile List<T> list = new LinkedList<>();
private volatile List<T> saveList ;
private volatile List<T> cleanList = new LinkedList<>();
private final IService<T> service;
private final Class<T> clazz;
private volatile int threadNum = 0;
public MybatisSaveMQ(IService<T> service,Class<T> clazz){
this.service = service;
this.clazz = clazz;
}
public void save(T t){
this.list.add(t);
if(threadNum < 3){
threadNum ++;
new Thread(){
@Override
public void run() {
synchronized (clazz){
saveList = list;
list = cleanList;
service.saveBatch(saveList);
cleanList = saveList;
cleanList.clear();
threadNum --;
}
}
}.start();
}
}
}
下面的是线程优化过的,并且增加了异常处理。单独维护一个保存线程,工作线程负责将数据压入队列,保存线程负责将队列中数据存入数据库
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.SneakyThrows;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* ClassName: MybatisSaveMQ
* Description: 保存队列
* date: 2021-03-19
*
* @since JDK 1.8
*/
public class MybatisSaveMQ<T> {
private volatile List<T> list = new LinkedList<>();
private volatile List<T> saveList ;
private volatile List<T> cleanList = new LinkedList<>();
private final IService<T> service;
private volatile int threadNum = 0;
private Thread workTread ;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public MybatisSaveMQ(IService<T> service){
this.service = service;
workTread = new Thread(){
@SneakyThrows
@Override
public void run() {
for (;;){
if(threadNum == 0){
lock.lock();
if(threadNum == 0){
condition.await();
}
lock.unlock();
}
saveList = list;
list = cleanList;
try {
service.saveBatch(saveList);
}catch (Exception e){
e.printStackTrace();
saveList.forEach(item ->{
try {
service.save(item);
}catch (Exception e1){
e1.printStackTrace();
}
});
}
cleanList = saveList;
cleanList.clear();
threadNum --;
}
}
};
workTread.start();
}
public void synchronized save(T t){
this.list.add(t);
if(threadNum < 2){
threadNum ++;
if(threadNum == 1){
lock.lock();
condition.signal();
lock.unlock();
}
}
}
}
该队列依靠所需工作线程数控制获取线程锁的逻辑,在高并发时没有线程锁的操作,两个线程几乎互不影响,没有性能损耗;
经测试,单纯的依靠mybatisPlus 原生save 方法逐条储存十万条数据到方法结束返回用时 1100多秒,同样的环境下,该队列将同样的数据压入队列并返回的时间为8毫秒,保存线程将数据批量存入数据库的时间为 32 秒