【发布时间】:2018-12-16 07:15:48
【问题描述】:
我在 MySQL 数据库中有一个非常大的表,表 Users 中有 2 亿条记录。
我使用 JDBC 进行查询:
public List<Pair<Long, String>> getUsersAll() throws SQLException {
Connection cnn = null;
CallableStatement cs = null;
ResultSet rs = null;
final List<Pair<Long, String>> res = new ArrayList<>();
try {
cnn = dataSource.getConnection();
cs = cnn.prepareCall("select UserPropertyKindId, login from TEST.users;");
rs = cs.executeQuery();
while (rs.next()) {
res.add(new ImmutablePair<>(rs.getLong(1), rs.getString(2)));
}
return res;
} catch (SQLException ex) {
throw ex;
} finally {
DbUtils.closeQuietly(cnn, cs, rs);
}
}
接下来,我处理结果:
List<Pair<Long, String>> users= dao.getUsersAll();
if (CollectionUtils.isNotEmpty(users)) {
for (List<Pair<Long, String>> partition : Lists.partition(users, 2000)) {
InconsistsUsers.InconsistsUsersCallable callable = new InconsistsUsers.InconsistsUsersCallable (new ArrayList<>(partition));
processExecutor.submit(callable);
}
}
但是由于表非常大并且全部卸载到内存中,我的应用程序崩溃并出现错误:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:通信链路故障
从服务器成功接收到的最后一个数据包是 105,619 毫秒前。
如何分批接收数据并按优先级顺序处理,不至于一次将所有结果上传到内存中?可以创建游标并将数据上传到非阻塞队列并在数据到达时对其进行处理。如何做到这一点?
更新:
我的数据库结构:https://www.db-fiddle.com/f/v377ZHkG1YZcdQsETtPm9L/3
当前算法:
从
Users表中获取所有数据用户:select UserPropertyKindId, login from Users;-
这个结果被分成2000对并提交给
ThreadPoolTaskExecutor:List<Pair<Long, String>> users= dao.getUsersAll(); if (CollectionUtils.isNotEmpty(users)) { for (List<Pair<Long, String>> partition : Lists.partition(users, 2000)) { InconsistsUsers.InconsistsUsersCallable callable = new InconsistsUsers.InconsistsUsersCallable(new ArrayList<>(partition)); processExecutor.submit(callable)); } } -
在 callable 中为每一对做两个查询:
第一个查询:
select distinct entityId from UserPropertyValue where userPropertyKindId= ? and value = ? -- value its login from Users table第二次查询:
select UserIds from UserPropertyIndex where UserPropertyKindId = ? and Value = ?
可能有两种情况:
- 第一个查询结果为空:记录,发送通知,继续下一个对
- 第二次查询的结果不等于第一次查询的结果(varbinary 数据已解码。存储了编码的 entityId)。然后记录,发送通知,转到下一对。
我不能改变基地的结构。我必须在 Java 代码方面进行的所有操作。
【问题讨论】:
-
您面临查询超时问题,请考虑增加相同
-
不要将所有用户都保存在内存中
-
@user7294900,我知道,这是不对的。但我不知道该怎么做
-
@All_Safe 你想达到什么目的?为什么要在内存中保存 2 亿条记录?
-
@user7294900,对于从这个表中收到的每个用户,都需要进行一定的处理和验证
标签: java mysql multithreading jdbc producer-consumer