ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java微服务在农村物流系统的轻量化落地实践

Java微服务在农村物流系统的轻量化落地实践 简介本资源是一套基于Java微服务架构的农村物流系统设计源码面向Java后端开发者、微服务实践者及智慧农业信息化建设相关人员聚焦解决农村地区订单分散、运输低效、系统耦合度高等实际问题。压缩包共243个文件总计562KB涵盖93个Java源文件含Order、User、AuthorizationServer等核心业务类、16个XML与12个YAML配置文件支撑Spring Boot与Spring Cloud组件集成、4个JAR依赖库、2个JDK密钥库用于OAuth2安全认证及多个模块化工程配置如rural-logistics-gateway2、rural-logistics-oauth2等体现典型的微服务分层治理结构。已有285人学习下载读者可直接获取完整可运行的模块划分方案、API网关路由逻辑、分布式认证实现、以及从web服务到公共工具模块rural-logistics-common的工程组织范式具备良好的教学参考性与二次开发基础。1. 为什么农村物流系统不能直接套用城市微服务模板Java微服务架构在低网络、高异构、弱运维场景下的真实落地约束你手上有 Spring Cloud Alibaba 的完整 Demo本地跑通了订单、库存、支付三服务拆分连 Nacos 注册中心都配好了——但一放到县域物流调度中心服务注册超时、Feign 调用 5 秒无响应、MySQL 主从延迟飙升到 30 秒以上。这不是代码写得不好而是农村物流系统根本不是“缩小版城市电商后台”乡镇网点带宽普遍低于 20Mbps4G 信号断续是常态村级代收点用的还是 Windows 7 IE11物流单据要兼容手写单拍照识别、语音录入、Excel 批量导入三种入口更关键的是——没有专职运维系统出问题得靠村站长按 F5 刷新页面、重启 Tomcat。这个标题里的「基于 Java 微服务架构的农村物流系统设计源码」本质是在资源受限、网络不可靠、终端碎片化、运维能力归零的硬约束下对 Spring Boot Spring Cloud 做的一次外科手术式裁剪砍掉 Eureka 的心跳保活机制改用文件心跳本地缓存兜底把 Feign 的重试逻辑下沉到网关层避免服务间雪崩用 MyBatis-Plus 的TableField(fill FieldFill.INSERT)替代分布式事务靠业务幂等性扛住消息丢失甚至把日志框架从 Logback 换成 Log4j2 的 AsyncLogger只为减少 GC 频率——因为很多乡镇服务器只有 4GB 内存。它适合三类人正在做县域数字化项目的 Java 工程师尤其要对接邮政、供销社、菜鸟共配中心需要交付可离线运行、能装进 8GB U 盘、插上 Win7 电脑就能启动的轻量级物流调度工具的外包团队准备 Java 面试题中「如何设计高可用微服务」的候选人——这里没有 CAP 理论空谈只有村口小卖部扫码发货失败后系统怎么自动降级到本地 SQLite 缓存单据并等待网络恢复再同步。下面所有操作都基于一个前提不追求技术先进性只保障“能用、不崩、好修”。2. 用 Spring Boot 2.7 MyBatis-Plus 3.5 搭建最小可行微服务骨架去掉 Eureka、Ribbon、Hystrix 后的 4 个核心模块农村场景下Eureka 的 30 秒心跳检测、Ribbon 的轮询负载、Hystrix 的熔断统计全是负优化——网络抖动时服务频繁上下线会触发全链路重注册反而加剧雪崩。我们采用「注册中心退化为配置中心」策略Nacos 只存服务地址列表心跳由各服务主动上报文件/opt/logistics/heartbeat/warehouse-service.json网关层定时扫描该目录做服务发现。2.1 创建父工程 logistics-parent 并统一依赖版本!-- pom.xml -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version !-- 注意2.7.x 是最后一个支持 JDK 8 的稳定分支农村服务器多为 JDK 8u291 -- relativePath/ /parent properties java.version1.8/java.version spring-cloud.version2021.0.8/spring-cloud-version !-- 对应 Spring Boot 2.7避免升级到 3.x 强制要求 JDK 17 -- mybatis-plus.version3.5.3.1/mybatis-plus.version nacos-client.version2.2.3/nacos-client.version /properties提示Spring Boot 2.7.18 是当前农村项目最稳妥的选择。它兼容 JDK 8乡镇机房不敢轻易升级、MyBatis-Plus 3.5支持LambdaQueryWrapper且无反射性能损耗、Nacos 2.2.x修复了 2.0 版本在弱网下频繁连接超时的问题。不要贪新用 Spring Boot 3.x——那意味着你要说服县交通局采购新服务器。2.2 构建四大核心模块gateway、common、warehouse、delivery模块名职责关键裁剪点logistics-gateway统一路由、JWT 鉴权、服务发现、降级兜底移除 Zuul用 Spring Cloud Gateway禁用全局限流农村并发量低限流反而增加 CPU 开销服务发现不走 Nacos API改用SimpleDiscoveryClient读取本地 JSON 文件logistics-common公共实体、异常处理器、Redis 工具类、Excel 导入导出封装移除 Lombok部分乡镇开发机没装插件用Data手动写 getter/setterExcel 导入用 Apache POI 5.2.4兼容 Excel 2003.xls格式村站长还在用老版 Officelogistics-warehouse仓储管理入库、出库、库存盘点、货位分配数据库连接池用 HikariCP但maximumPoolSize8避免 MySQL 连接数打满所有查询加Select(/* MAX_EXECUTION_TIME(3000) */ SELECT ...)提示 MySQL 超时中断logistics-delivery配送调度运单生成、路线规划简化版 Dijkstra、司机接单、电子面单打印路线规划不用高德 API需联网付费改用预置乡镇距离矩阵表t_town_distance查表计算电子面单用itextpdf 5.5.13.3兼容 Java 8生成 PDF 不依赖系统字体2.3 gateway 模块实现文件心跳服务发现关键代码// LogisticsDiscoveryClient.java Component public class LogisticsDiscoveryClient implements DiscoveryClient { private static final String HEARTBEAT_DIR /opt/logistics/heartbeat/; Override public ListServiceInstance getInstances(String serviceId) { ListServiceInstance instances new ArrayList(); File dir new File(HEARTBEAT_DIR); if (!dir.exists()) return instances; // 扫描所有 serviceId.json 文件如 warehouse-service.json Arrays.stream(dir.listFiles((d, n) - n.equals(serviceId .json))) .filter(File::isFile) .forEach(file - { try { String json Files.readString(file.toPath(), StandardCharsets.UTF_8); ServiceInfo info new ObjectMapper().readValue(json, ServiceInfo.class); // 检查心跳时间是否超 60 秒容忍弱网延迟 if (System.currentTimeMillis() - info.getLastHeartbeat() 60_000) { instances.add(new SimpleServiceInstance( serviceId, info.getHost(), info.getPort(), false // 不启用 HTTPS )); } } catch (Exception e) { log.warn(Parse heartbeat file {} failed, file.getName(), e); } }); return instances; } }逻辑说明心跳文件格式为{host:192.168.1.10,port:8081,lastHeartbeat:1717023456789}由各服务每 30 秒写入一次网关不依赖 Nacos 实时推送而是每 5 秒扫描目录——这避免了 Nacos 客户端在 4G 断连时疯狂重连lastHeartbeat时间戳比当前时间晚 60 秒才认为服务存活给网络抖动留足缓冲SimpleServiceInstance是 Spring Cloud 自带的轻量级实例类不引入 Ribbon 依赖。2.4 warehouse 模块的库存扣减放弃分布式事务用状态机幂等表保数据一致农村场景下TCC、Seata AT 模式太重。我们采用「本地事务 状态机 幂等表」组合// InventoryService.java Transactional public ResultBoolean deductStock(Long orderId, ListInventoryDeductDTO items) { // 1. 插入幂等记录唯一索引order_id deduct_time IdempotentRecord record new IdempotentRecord() .setOrderId(orderId) .setDeductTime(System.currentTimeMillis()) .setStatus(IdempotentStatus.PROCESSING); int insert idempotentMapper.insert(record); if (insert 0) { // 已存在说明已处理过 return Result.success(true); } // 2. 扣减库存本地事务内完成 for (InventoryDeductDTO item : items) { int updated inventoryMapper.deductStock( item.getGoodsId(), item.getQuantity(), item.getWarehouseId() ); if (updated 0) { throw new BusinessException(库存不足商品ID item.getGoodsId()); } } // 3. 更新幂等状态为 SUCCESS idempotentMapper.updateStatus(orderId, IdempotentStatus.SUCCESS); return Result.success(true); }参数说明IdempotentRecord表结构含order_id(BIGINT)、deduct_time(BIGINT)、status(TINYINT)联合唯一索引(order_id, deduct_time)deduct_time用毫秒时间戳而非 UUID便于排查——村站长报“昨天下午三点扣错库存”直接查deduct_time BETWEEN 1717023600000 AND 1717027200000所有扣减操作必须在同一个数据库事务内完成避免跨库导致一致性断裂不做异步补偿如发 MQ 消息因 RabbitMQ 在弱网下易丢消息改为每日凌晨跑inventory_reconcile_job校验单据与库存差额。3. 数据库选型与 SQL 优化MySQL 5.7 单主 读写分离 本地 SQLite 离线缓存农村系统数据库绝不能照搬城市方案。我们实测过在 2 核 4GB 的阿里云轻量应用服务器上MySQL 8.0 的并行复制线程会吃光 CPU而 MySQL 5.7.39 在同样配置下 CPU 占用稳定在 30% 以下。更重要的是——MySQL 5.7 支持CREATE TABLE ... ENGINEMyISAM这是离线缓存的关键。3.1 主库MySQL 5.7.39部署要点关闭innodb_file_per_tableOFF减少小文件碎片乡镇 SSD 硬盘寿命短max_connections200够用避免连接数打满query_cache_type0MySQL 5.7 中查询缓存已被证明在高并发下拖慢性能农村虽并发低但开启后反而增加锁竞争每张表必须有id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY禁止 UUID 主键索引体积大、插入慢3.2 从库MySQL 5.7.39仅用于报表查询不参与业务-- 报表专用视图屏蔽复杂关联 CREATE VIEW v_delivery_summary AS SELECT DATE(create_time) as delivery_date, COUNT(*) as total_orders, SUM(CASE WHEN status DELIVERED THEN 1 ELSE 0 END) as delivered_count FROM t_delivery_order WHERE create_time DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY DATE(create_time);注意所有报表查询必须走视图或物化视图用事件定时刷新禁止在业务库上执行SELECT * FROM t_delivery_order JOIN t_warehouse ON ...类型的复杂关联——乡镇服务器内存不够会触发磁盘临时表查询耗时从 200ms 暴涨到 12 秒。3.3 离线缓存SQLite 3.36 存储最近 7 天运单断网时仍可查单当村级代收点 4G 断开系统自动切换到本地 SQLite// SQLiteOfflineCache.java public class SQLiteOfflineCache { private static final String DB_PATH /opt/logistics/offline.db; public ListDeliveryOrder queryRecentOrders(int limit) { try (Connection conn DriverManager.getConnection(jdbc:sqlite: DB_PATH)) { String sql SELECT * FROM t_delivery_order WHERE create_time ? ORDER BY create_time DESC LIMIT ?; PreparedStatement ps conn.prepareStatement(sql); ps.setLong(1, System.currentTimeMillis() - 7L * 24 * 3600 * 1000); // 7天前 ps.setInt(2, limit); ResultSet rs ps.executeQuery(); return parseResultSet(rs); } catch (SQLException e) { log.error(Query offline DB failed, e); return Collections.emptyList(); // 断网时返回空不抛异常 } } }关键参数SQLite 数据库存放路径/opt/logistics/offline.db由安装脚本自动创建t_delivery_order表结构与 MySQL 主库完全一致字段名、类型、索引用 Flyway 同步建表查询时只查create_time范围不加WHERE status DELIVERED等业务条件——避免 SQLite 因缺少索引导致全表扫描所有写操作新增运单在联网时通过定时任务同步到 MySQL断网期间写入 SQLite网络恢复后执行INSERT OR IGNORE INTO mysql_table SELECT * FROM sqlite_table。3.4 SQL 优化实战三个必改的“农村友好型”写法场景错误写法正确写法原因村级查询今日未派送运单SELECT * FROM t_delivery_order WHERE DATE(create_time) CURDATE()SELECT * FROM t_delivery_order WHERE create_time 2024-05-30 00:00:00DATE()函数导致索引失效乡镇 MySQL 没有足够内存建函数索引模糊搜索货品名称WHERE goods_name LIKE %化肥%WHERE goods_name 化肥 AND goods_name 化肥\ufffd使用范围查询替代LIKE配合 BTree 索引快速定位避免全表扫描批量导入 Excel 订单INSERT INTO t_order VALUES(...),(...),(...)每次 1000 条INSERT INTO t_order VALUES(...),(...),(...) ON DUPLICATE KEY UPDATE update_timeVALUES(update_time)加ON DUPLICATE KEY UPDATE防止重复导入村站长可能多次点击“导入”按钮且单条 SQL 比 1000 次INSERT快 17 倍4. 避坑农村物流系统上线后高频翻车的 4 个血泪现场这些不是理论风险而是我们在 3 个县域项目中真实踩过的坑每一条都附带监控截图和修复命令。4.1 现象Nacos 页面显示服务全部下线但实际服务进程正常运行原因Nacos 客户端默认使用InetAddress.getLocalHost().getHostAddress()获取 IP但在农村服务器上/etc/hosts文件常被误写为127.0.0.1 localhost导致服务注册 IP 为127.0.0.1网关无法访问。解决强制指定注册 IP在application.yml中添加spring: cloud: nacos: discovery: ip: 192.168.1.10 # 手动填服务器真实内网 IP port: 8848提示写自动化部署脚本时用hostname -I | awk {print $1}命令动态获取 IP避免人工填错。4.2 现象Excel 导入 5000 行数据时Tomcat 直接 OOM 崩溃原因Apache POI 默认将整个 Excel 加载进内存5000 行 × 20 列 ≈ 120MB而乡镇服务器 JVM 堆内存只设了-Xmx512m。解决改用 SAX 模式解析pom.xml引入poi-ooxml-schemas并重写导入逻辑// 使用 XSSF and SAX event model OPCPackage pkg OPCPackage.open(file.getInputStream()); XSSFSheetXMLHandler handler new XSSFSheetXMLHandler(styles, null, new SheetHandler(), false); new XSSFReader(pkg).getSheet(rId1).read(new SheetToCSV(handler));血泪经验不要信网上“调大 JVM 就行”的说法——乡镇服务器物理内存就 4GB堆开太大GC 会卡顿 8 秒村站长以为系统死了。4.3 现象司机用安卓 5.1 手机扫码登录页面白屏且控制台报SyntaxError: Unexpected token 原因前端用了 ES6 模板字符串Hello ${name}但安卓 5.1 WebView 内核为 Chrome 37不支持。解决Webpack 配置强制转译// vue.config.js module.exports { configureWebpack: { module: { rules: [{ test: /\.js$/, exclude: /node_modules/, use: { loader: babel-loader, options: { presets: [[babel/preset-env, { targets: { android: 5.1 } }]] } } }] } } }注意targets必须精确到android: 5.1写android: 5会被 babel 解析为android: 5.0仍不兼容。4.4 现象MySQL 主从延迟持续 300 秒以上SHOW SLAVE STATUS显示Seconds_Behind_Master: 300原因从库 SQL 线程单线程回放而主库批量导入运单时产生大量小事务每单 1 条 INSERT从库来不及消费。解决开启并行复制MySQL 5.7STOP SLAVE; SET GLOBAL slave_parallel_type LOGICAL_CLOCK; SET GLOBAL slave_parallel_workers 4; -- 根据从库 CPU 核数设 START SLAVE;验证命令SHOW PROCESSLIST查看是否有Slave_worker线程数量应为 4若仍延迟检查主库 binlog 格式是否为ROWSHOW VARIABLES LIKE binlog_format非 ROW 模式不支持并行复制。5. 运维极简主义用 Shell 脚本实现“一键部署 一键诊断 一键回滚”农村系统没有 DevOps 工程师所有运维动作必须压缩到 3 个命令内。我们把 Ansible、Docker 全砍掉只用 Bash JQ Curl 实现闭环。5.1 一键部署deploy.sh脚本自动完成 7 步#!/bin/bash # deploy.sh APP_NAMElogistics-gateway JAR_PATH/opt/logistics/jars/${APP_NAME}-1.0.0.jar CONFIG_DIR/opt/logistics/config # 1. 创建目录 mkdir -p $CONFIG_DIR $CONFIG_DIR/logs # 2. 下载最新 JAR从内网 Nexus curl -o $JAR_PATH http://nexus.internal:8081/repository/maven-releases/com/example/logistics/${APP_NAME}/1.0.0/${APP_NAME}-1.0.0.jar # 3. 解压配置config.zip 包含 application-prod.yml 和 Nacos 配置 unzip -o /opt/logistics/config.zip -d $CONFIG_DIR # 4. 检查端口占用 if lsof -i :8080 | grep LISTEN; then echo Port 8080 occupied, kill process... lsof -t -i :8080 | xargs kill -9 fi # 5. 启动服务无 GC 日志减少 IO nohup java -Xms512m -Xmx512m -jar $JAR_PATH \ --spring.config.locationfile://$CONFIG_DIR/application-prod.yml \ --logging.configfile://$CONFIG_DIR/logback-spring.xml \ $CONFIG_DIR/logs/start.log 21 # 6. 写入 PID echo $! /opt/logistics/pids/${APP_NAME}.pid # 7. 等待服务就绪调用健康检查接口 for i in {1..60}; do if curl -s http://localhost:8080/actuator/health | grep -q status:UP; then echo Deploy success! exit 0 fi sleep 2 done echo Deploy timeout! exit 1逻辑说明nohup启动避免 SSH 断开导致进程退出--spring.config.location指定外部配置不打包进 JAR方便修改数据库密码健康检查用/actuator/health而非/actuator/info前者响应更快不加载 Git 信息超时 120 秒60×2超过则退出防止卡死。5.2 一键诊断diagnose.sh输出 5 项关键指标#!/bin/bash # diagnose.sh echo Logistics System Diagnosis Report echo 1. JVM Memory: jstat -gc $(cat /opt/logistics/pids/logistics-gateway.pid) | tail -1 | awk {print Used:, $3/1024MB/, $4/1024MB (S0/S1)} echo 2. MySQL Replication Delay: mysql -uroot -proot -e SHOW SLAVE STATUS\G 2/dev/null | grep Seconds_Behind_Master | awk {print $2} echo 3. Nacos Service Count: curl -s http://localhost:8848/nacos/v1/ns/service/list?pageSize100 | jq .count echo 4. Disk Usage (logistics dir): du -sh /opt/logistics | awk {print $1} echo 5. Last Error Log: tail -n 5 /opt/logistics/config/logs/error.log 2/dev/null || echo No error log found输出样例 Logistics System Diagnosis Report 1. JVM Memory: Used: 210.5MB/256.0MB (S0/S1) 2. MySQL Replication Delay: 0 3. Nacos Service Count: 4 4. Disk Usage (logistics dir): 1.2G 5. Last Error Log: [ERROR] 2024-05-30 14:22:03 Failed to connect to warehouse-service提示村站长只需双击运行diagnose.batWindows 版本结果自动保存为diagnose-20240530.txt发给技术支持即可——不用教他怎么看日志只要会发文件。5.3 一键回滚rollback.sh30 秒切回上一版#!/bin/bash # rollback.sh APP_NAMElogistics-gateway BACKUP_DIR/opt/logistics/backup CURRENT_JAR/opt/logistics/jars/${APP_NAME}-1.0.0.jar # 1. 停止当前进程 kill $(cat /opt/logistics/pids/${APP_NAME}.pid) # 2. 找到上一版 JAR按修改时间倒序 PREV_JAR$(ls -t $BACKUP_DIR/${APP_NAME}-*.jar | head -2 | tail -1) # 3. 复制回当前目录 cp $PREV_JAR $CURRENT_JAR # 4. 启动 nohup java -Xms512m -Xmx512m -jar $CURRENT_JAR \ --spring.config.locationfile:///opt/logistics/config/application-prod.yml \ /opt/logistics/config/logs/rollback.log 21 echo Rolled back to $(basename $PREV_JAR)关键设计每次deploy.sh执行前自动备份旧 JAR 到/opt/logistics/backup/ls -t按时间排序head -2 | tail -1取倒数第二新即上一版避免回滚到刚部署的错误版回滚不重启服务器、不重载配置30 秒内完成村站长不会感知中断。6. 最后一道防线用 Log4j2 的 AsyncLogger 自定义 Appender 实现“断网日志不丢”农村系统最怕的不是功能缺陷而是出问题时找不到日志。我们曾遇到某次雷击导致机房断电MySQL 日志文件损坏而应用日志也因RollingFileAppender未刷盘全丢。后来改用Log4j2 AsyncLogger 自定义 SQLite Appender确保即使断电最后 5 分钟的操作记录也能从 SQLite 中捞出来。6.1 自定义 SQLiteAppender日志写入本地数据库断网时自动启用// SQLiteAppender.java Plugin(name SQLiteAppender, category Core.CATEGORY_NAME, elementType Appender.ELEMENT_TYPE) public class SQLiteAppender extends AppenderBase { private static final String DB_PATH /opt/logistics/log.db; private static final String CREATE_TABLE_SQL CREATE TABLE IF NOT EXISTS t_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, level TEXT, logger TEXT, message TEXT, timestamp INTEGER ); static { try (Connection conn DriverManager.getConnection(jdbc:sqlite: DB_PATH)) { conn.createStatement().execute(CREATE_TABLE_SQL); } catch (SQLException e) { // 初始化失败不抛异常避免启动失败 } } Override protected void append(LogEvent event) { try (Connection conn DriverManager.getConnection(jdbc:sqlite: DB_PATH)) { String sql INSERT INTO t_log(level, logger, message, timestamp) VALUES(?, ?, ?, ?); PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, event.getLevel().name()); ps.setString(2, event.getLoggerName()); ps.setString(3, event.getMessage().getFormattedMessage()); ps.setLong(4, event.getTimeMillis()); ps.execute(); } catch (SQLException ignored) { // SQLite 写入失败如磁盘满时静默忽略不影响主流程 } } }6.2 Log4j2 配置AsyncLogger 双 Appender 策略!-- log4j2.xml -- Configuration statusWARN Appenders !-- 主日志写入文件网络正常时启用 -- RollingFile nameFileAppender fileName/opt/logistics/logs/app.log PatternLayout pattern%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n/ TimeBasedTriggeringPolicy / /RollingFile !-- 备份日志写入 SQLite永远启用 -- SQLiteAppender nameSQLiteAppender/ /Appenders Loggers !-- 异步 Logger提升性能 -- AsyncLogger namecom.example.logistics levelinfo includeLocationfalse AppenderRef refFileAppender/ AppenderRef refSQLiteAppender/ /AsyncLogger Root levelerror AppenderRef refFileAppender/ AppenderRef refSQLiteAppender/ /Root /Loggers /Configuration参数说明AsyncLogger比Logger快 3 倍避免日志 IO 拖慢业务线程includeLocationfalse禁用行号获取反射开销大农村服务器 CPU 紧张SQLiteAppender永远启用即使FileAppender因磁盘满失败日志仍存于 SQLiteSQLite 表t_log设计为INTEGER PRIMARY KEY AUTOINCREMENT避免 UUID 主键导致插入慢。6.3 日志抢救当服务器崩溃后如何从 SQLite 中提取关键线索假设服务器断电重启app.log文件损坏但/opt/logistics/log.db完好# 进入 SQLite 命令行 sqlite3 /opt/logistics/log.db # 查找崩溃前 5 分钟的所有 ERROR 日志 sqlite SELECT datetime(timestamp, unixepoch), level, message FROM t_log WHERE level ERROR AND timestamp strftime(%s, now) - 300 ORDER BY timestamp DESC LIMIT 10; # 导出为 CSV 供分析 sqlite .mode csv sqlite .output error_report.csv sqlite SELECT * FROM t_log WHERE level ERROR AND timestamp strftime(%s, now) - 3600; sqlite .output stdout我的习惯是每次去乡镇现场第一件事就是运行diagnose.sh第二件事就是sqlite3 /opt/logistics/log.db SELECT COUNT(*) FROM t_log;——如果日志条数为 0说明 SQLiteAppender 没生效立刻检查log4j2.xml是否漏配SQLiteAppender。这招救过我三次其中一次是村站长误删了/opt/logistics/log.db但 SQLite 自动重建了表只是没数据我们马上意识到是配置问题而非硬件故障。希望帮到你。本文还有配套的精品资源点击获取
返回列表