缩小日志事务
This commit is contained in:
1 parent
3557a1f1a4
commit
621e078031
2 files changed
+83
-75
No files matched your search
+82
-74
@@ -3,9 +3,9 @@ package com.bsd.pjcloud.admin.service.impl.stats;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.bsd.pjcloud.admin.api.dto.stats.AppAccessStatsQueryDTO;
|
||||
import com.bsd.pjcloud.admin.api.dto.stats.AppAccessTrackRequestDTO;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDept;
|
||||
@@ -26,6 +26,7 @@ import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -51,16 +52,10 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService {
|
||||
private final SysDeptMapper sysDeptMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Boolean> track(AppAccessTrackRequestDTO dto, HttpServletRequest request) {
|
||||
if (!isPageCodeEnabled(dto.getPageCode())) {
|
||||
return R.failed("pageCode未在埋点字典中启用: " + dto.getPageCode());
|
||||
}
|
||||
Long exists = appAccessEventMapper.selectCount(new LambdaQueryWrapper<AppAccessEventEntity>()
|
||||
.eq(AppAccessEventEntity::getEventId, dto.getEventId()));
|
||||
if (exists != null && exists > 0) {
|
||||
return R.ok(Boolean.TRUE);
|
||||
}
|
||||
|
||||
LocalDateTime eventTime = ObjectUtil.defaultIfNull(dto.getEventTime(), LocalDateTime.now());
|
||||
PjcloudUser loginUser = SecurityUtils.getUser();
|
||||
@@ -85,7 +80,11 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService {
|
||||
entity.setUnitName(orgInfo.unitName);
|
||||
entity.setDeptId(orgInfo.deptId);
|
||||
entity.setDeptName(orgInfo.deptName);
|
||||
appAccessEventMapper.insert(entity);
|
||||
try {
|
||||
appAccessEventMapper.insert(entity);
|
||||
} catch (DuplicateKeyException ex) {
|
||||
return R.ok(Boolean.TRUE);
|
||||
}
|
||||
return R.ok(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@@ -262,34 +261,19 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void aggregateLastMinute() {
|
||||
LocalDateTime end = LocalDateTime.now().withSecond(0).withNano(0);
|
||||
LocalDateTime start = end.minusMinutes(1);
|
||||
List<Map<String, Object>> rows = queryEventAggRows(start, end);
|
||||
getSelf().persistMinuteAggregation(start, rows);
|
||||
}
|
||||
|
||||
QueryWrapper<AppAccessEventEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select(
|
||||
"tenant_id as tenantId",
|
||||
"unit_id as unitId",
|
||||
"max(unit_name) as unitName",
|
||||
"dept_id as deptId",
|
||||
"max(dept_name) as deptName",
|
||||
"page_code as pageCode",
|
||||
"count(1) as pv",
|
||||
"count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv",
|
||||
"count(distinct user_id) as visitUserCount",
|
||||
"count(1) as trackCount"
|
||||
);
|
||||
queryWrapper.ge("event_time", start);
|
||||
queryWrapper.lt("event_time", end);
|
||||
queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code");
|
||||
List<Map<String, Object>> rows = appAccessEventMapper.selectMaps(queryWrapper);
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void persistMinuteAggregation(LocalDateTime start, List<Map<String, Object>> rows) {
|
||||
appAccessAggMinuteMapper.deletePhysicallyByBucketTime(start);
|
||||
if (CollUtil.isEmpty(rows)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Map<String, Object> row : rows) {
|
||||
AppAccessAggMinuteEntity entity = new AppAccessAggMinuteEntity();
|
||||
entity.setBucketTime(start);
|
||||
@@ -308,52 +292,63 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void aggregateRecentDays(int dayCount) {
|
||||
int safeDayCount = Math.max(dayCount, 1);
|
||||
LocalDate today = LocalDate.now();
|
||||
for (int i = 0; i < safeDayCount; i++) {
|
||||
LocalDate date = today.minusDays(i);
|
||||
LocalDateTime start = date.atStartOfDay();
|
||||
LocalDateTime end = start.plusDays(1);
|
||||
|
||||
QueryWrapper<AppAccessEventEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select(
|
||||
"tenant_id as tenantId",
|
||||
"unit_id as unitId",
|
||||
"max(unit_name) as unitName",
|
||||
"dept_id as deptId",
|
||||
"max(dept_name) as deptName",
|
||||
"page_code as pageCode",
|
||||
"count(1) as pv",
|
||||
"count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv",
|
||||
"count(distinct user_id) as visitUserCount",
|
||||
"count(1) as trackCount"
|
||||
);
|
||||
queryWrapper.ge("event_time", start);
|
||||
queryWrapper.lt("event_time", end);
|
||||
queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code");
|
||||
List<Map<String, Object>> rows = appAccessEventMapper.selectMaps(queryWrapper);
|
||||
|
||||
appAccessAggDayMapper.deletePhysicallyByStatDate(date);
|
||||
for (Map<String, Object> row : rows) {
|
||||
AppAccessAggDayEntity entity = new AppAccessAggDayEntity();
|
||||
entity.setStatDate(date);
|
||||
entity.setTenantId(toLongObj(row.get("tenantId")));
|
||||
entity.setUnitId(toLongObj(row.get("unitId")));
|
||||
entity.setUnitName(Objects.toString(row.get("unitName"), null));
|
||||
entity.setDeptId(toLongObj(row.get("deptId")));
|
||||
entity.setDeptName(Objects.toString(row.get("deptName"), null));
|
||||
entity.setPageCode(Objects.toString(row.get("pageCode"), null));
|
||||
entity.setPv(toLong(row.get("pv")));
|
||||
entity.setUv(toLong(row.get("uv")));
|
||||
entity.setVisitUserCount(toLong(row.get("visitUserCount")));
|
||||
entity.setTrackCount(toLong(row.get("trackCount")));
|
||||
appAccessAggDayMapper.insert(entity);
|
||||
try {
|
||||
List<Map<String, Object>> rows = queryEventAggRows(date.atStartOfDay(), date.plusDays(1).atStartOfDay());
|
||||
getSelf().persistDayAggregation(date, rows);
|
||||
} catch (Exception e) {
|
||||
log.error("日聚合失败 date={}", date, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void persistDayAggregation(LocalDate date, List<Map<String, Object>> rows) {
|
||||
appAccessAggDayMapper.deletePhysicallyByStatDate(date);
|
||||
if (CollUtil.isEmpty(rows)) {
|
||||
return;
|
||||
}
|
||||
for (Map<String, Object> row : rows) {
|
||||
AppAccessAggDayEntity entity = new AppAccessAggDayEntity();
|
||||
entity.setStatDate(date);
|
||||
entity.setTenantId(toLongObj(row.get("tenantId")));
|
||||
entity.setUnitId(toLongObj(row.get("unitId")));
|
||||
entity.setUnitName(Objects.toString(row.get("unitName"), null));
|
||||
entity.setDeptId(toLongObj(row.get("deptId")));
|
||||
entity.setDeptName(Objects.toString(row.get("deptName"), null));
|
||||
entity.setPageCode(Objects.toString(row.get("pageCode"), null));
|
||||
entity.setPv(toLong(row.get("pv")));
|
||||
entity.setUv(toLong(row.get("uv")));
|
||||
entity.setVisitUserCount(toLong(row.get("visitUserCount")));
|
||||
entity.setTrackCount(toLong(row.get("trackCount")));
|
||||
appAccessAggDayMapper.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> queryEventAggRows(LocalDateTime start, LocalDateTime end) {
|
||||
QueryWrapper<AppAccessEventEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select(
|
||||
"tenant_id as tenantId",
|
||||
"unit_id as unitId",
|
||||
"max(unit_name) as unitName",
|
||||
"dept_id as deptId",
|
||||
"max(dept_name) as deptName",
|
||||
"page_code as pageCode",
|
||||
"count(1) as pv",
|
||||
"count(distinct if(user_id is null, concat('D_', ifnull(device_id,'')), concat('U_', user_id))) as uv",
|
||||
"count(distinct user_id) as visitUserCount",
|
||||
"count(1) as trackCount"
|
||||
);
|
||||
queryWrapper.ge("event_time", start);
|
||||
queryWrapper.lt("event_time", end);
|
||||
queryWrapper.groupBy("tenant_id", "unit_id", "dept_id", "page_code");
|
||||
return appAccessEventMapper.selectMaps(queryWrapper);
|
||||
}
|
||||
|
||||
private boolean isPageCodeEnabled(String pageCode) {
|
||||
Long count = appAccessPageDictMapper.selectCount(new LambdaQueryWrapper<AppAccessPageDictEntity>()
|
||||
.eq(AppAccessPageDictEntity::getPageCode, pageCode)
|
||||
@@ -427,22 +422,35 @@ public class AppAccessStatsServiceImpl implements AppAccessStatsService {
|
||||
.last("limit 1"));
|
||||
|
||||
if (currentSnapshot == null) {
|
||||
DimUserOrgSnapshotEntity inserted = insertSnapshot(userId, userTenantId, unitDept, dept, eventTime);
|
||||
return toOrgInfo(inserted);
|
||||
return getSelf().insertOrgSnapshotTx(userId, userTenantId, unitDept, dept, eventTime);
|
||||
}
|
||||
|
||||
if (isOrgSnapshotOutdated(currentSnapshot, unitDept, dept)) {
|
||||
DimUserOrgSnapshotEntity update = new DimUserOrgSnapshotEntity();
|
||||
update.setSnapshotSk(currentSnapshot.getSnapshotSk());
|
||||
update.setIsCurrent(0);
|
||||
update.setEffectiveEndTime(eventTime);
|
||||
dimUserOrgSnapshotMapper.updateById(update);
|
||||
DimUserOrgSnapshotEntity inserted = insertSnapshot(userId, userTenantId, unitDept, dept, eventTime);
|
||||
return toOrgInfo(inserted);
|
||||
return getSelf().rotateOrgSnapshotTx(userId, userTenantId, unitDept, dept, eventTime, currentSnapshot);
|
||||
}
|
||||
return toOrgInfo(currentSnapshot);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public OrgInfo insertOrgSnapshotTx(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime) {
|
||||
return toOrgInfo(insertSnapshot(userId, tenantId, unitDept, dept, eventTime));
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public OrgInfo rotateOrgSnapshotTx(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime,
|
||||
DimUserOrgSnapshotEntity currentSnapshot) {
|
||||
DimUserOrgSnapshotEntity update = new DimUserOrgSnapshotEntity();
|
||||
update.setSnapshotSk(currentSnapshot.getSnapshotSk());
|
||||
update.setIsCurrent(0);
|
||||
update.setEffectiveEndTime(eventTime);
|
||||
dimUserOrgSnapshotMapper.updateById(update);
|
||||
return toOrgInfo(insertSnapshot(userId, tenantId, unitDept, dept, eventTime));
|
||||
}
|
||||
|
||||
private AppAccessStatsServiceImpl getSelf() {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
|
||||
private DimUserOrgSnapshotEntity insertSnapshot(Long userId, Long tenantId, SysDept unitDept, SysDept dept, LocalDateTime eventTime) {
|
||||
DimUserOrgSnapshotEntity snapshot = new DimUserOrgSnapshotEntity();
|
||||
snapshot.setUserId(userId);
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public class AppAccessStatsAggregateTask {
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 10 * * * ?")
|
||||
@Scheduled(cron = "0 15 * * * ?")
|
||||
public void aggregateDay() {
|
||||
try {
|
||||
appAccessStatsService.aggregateRecentDays(2);
|
||||
|
||||
Reference in new issue
Block a user