Jelajahi Sumber

天虹数据库备份

liuwei 3 bulan lalu
induk
melakukan
06f4c473a7

+ 276 - 0
src/main/java/com/jeesite/modules/scheduling/TianhongBackupScheduling.java

@@ -0,0 +1,276 @@
+package com.jeesite.modules.scheduling;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.modules.tianHong.dao.MachineAttrHistoryDao;
+import com.jeesite.modules.tianHong.dao.MachineAttrStateDao;
+import com.jeesite.modules.tianHong.entity.MachineAttrHistory;
+import com.jeesite.modules.tianHong.entity.MachineAttrState;
+
+/**
+ * 天虹浇筑历史备份:每10分钟整点(00/10/20/30/40/50)
+ * 备份上一完整窗口 [T-10min, T) 到主库 mes_cloud_ljr.tianhong_backup
+ * 曲线字段:秒级 600 槽,值用 # 分隔,缺秒留空
+ */
+@Configuration
+@EnableScheduling
+public class TianhongBackupScheduling {
+
+	private static final Logger log = LoggerFactory.getLogger(TianhongBackupScheduling.class);
+
+	private static final int POINT_COUNT = 600;
+
+	private static final String UPSERT_SQL =
+			"INSERT INTO tianhong_backup ("
+			+ "eqp_id, window_start, window_end,"
+			+ "cru_temp, alu_temp, mould_info,"
+			+ "theory_pressure, real_pressure, pressure_level, ele_consume,"
+			+ "alu_val, pressurize_time, cooling_time, pre_pres, hold_pressure, mold_filling_pre,"
+			+ "point_count, create_date, update_date"
+			+ ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW()) "
+			+ "ON DUPLICATE KEY UPDATE "
+			+ "window_end=VALUES(window_end),"
+			+ "cru_temp=VALUES(cru_temp), alu_temp=VALUES(alu_temp), mould_info=VALUES(mould_info),"
+			+ "theory_pressure=VALUES(theory_pressure), real_pressure=VALUES(real_pressure),"
+			+ "pressure_level=VALUES(pressure_level), ele_consume=VALUES(ele_consume),"
+			+ "alu_val=VALUES(alu_val), pressurize_time=VALUES(pressurize_time),"
+			+ "cooling_time=VALUES(cooling_time), pre_pres=VALUES(pre_pres),"
+			+ "hold_pressure=VALUES(hold_pressure), mold_filling_pre=VALUES(mold_filling_pre),"
+			+ "point_count=VALUES(point_count), update_date=NOW()";
+
+	@Autowired
+	private MachineAttrHistoryDao machineAttrHistoryDao;
+
+	@Autowired
+	private MachineAttrStateDao machineAttrStateDao;
+
+	@Autowired
+	private DataSource dataSource;
+
+	/**
+	 * 每10分钟整点执行:备份刚结束的窗口
+	 * 例:14:10:00 执行时备份 [14:00:00, 14:10:00)
+	 */
+	@Scheduled(cron = "0 0/10 * * * ?")
+	public void backupLastClosedWindow() {
+		Date end = floorTo10Minutes(new Date());
+		Date start = addMinutes(end, -10);
+		log.info("tianhong_backup start, window=[{}, {})", format(start), format(end));
+		List<MachineAttrState> devices;
+		try {
+			devices = machineAttrStateDao.findList(new MachineAttrState());
+		} catch (Exception e) {
+			log.error("tianhong_backup list devices failed", e);
+			return;
+		}
+		if (devices == null || devices.isEmpty()) {
+			log.warn("tianhong_backup no devices");
+			return;
+		}
+		int ok = 0;
+		for (MachineAttrState device : devices) {
+			if (device == null || StringUtils.isBlank(device.getEqpId())) {
+				continue;
+			}
+			try {
+				backupOne(device.getEqpId(), start, end);
+				ok++;
+			} catch (Exception e) {
+				log.error("tianhong_backup failed eqpId={}", device.getEqpId(), e);
+			}
+		}
+		log.info("tianhong_backup done, devices={}, ok={}", devices.size(), ok);
+	}
+
+	private void backupOne(String eqpId, Date start, Date end) throws Exception {
+		String cru = toSeries(machineAttrHistoryDao.findCruInRange(eqpId, start, end), start, "cru");
+		String alu = toSeries(machineAttrHistoryDao.findAluInRange(eqpId, start, end), start, "alu");
+		String mould = toMouldSeries(machineAttrHistoryDao.findMouldInRange(eqpId, start, end), start);
+		List<MachineAttrHistory> pressureList = machineAttrHistoryDao.findPressureInRange(eqpId, start, end);
+		String theory = toSeries(pressureList, start, "theory");
+		String real = toSeries(pressureList, start, "real");
+		String level = toSeries(pressureList, start, "level");
+		String ele = toSeries(machineAttrHistoryDao.findEleInRange(eqpId, start, end), start, "ele");
+
+		String aluVal = toAttrSeries(eqpId, "alu_val", start, end);
+		String pressurize = toAttrSeries(eqpId, "pressurizeTime", start, end);
+		String cooling = toAttrSeries(eqpId, "coolingTime", start, end);
+		String prePres = toAttrSeries(eqpId, "PrePres", start, end);
+		String hold = toAttrSeries(eqpId, "HoldPressure", start, end);
+		String moldPre = toAttrSeries(eqpId, "moldFillingPre", start, end);
+
+		try (Connection conn = dataSource.getConnection()) {
+			conn.setAutoCommit(true);
+			try (PreparedStatement ps = conn.prepareStatement(UPSERT_SQL)) {
+				int i = 1;
+				ps.setString(i++, eqpId);
+				ps.setTimestamp(i++, new Timestamp(start.getTime()));
+				ps.setTimestamp(i++, new Timestamp(end.getTime()));
+				ps.setString(i++, cru);
+				ps.setString(i++, alu);
+				ps.setString(i++, mould);
+				ps.setString(i++, theory);
+				ps.setString(i++, real);
+				ps.setString(i++, level);
+				ps.setString(i++, ele);
+				ps.setString(i++, aluVal);
+				ps.setString(i++, pressurize);
+				ps.setString(i++, cooling);
+				ps.setString(i++, prePres);
+				ps.setString(i++, hold);
+				ps.setString(i++, moldPre);
+				ps.setInt(i++, POINT_COUNT);
+				ps.executeUpdate();
+			}
+		}
+	}
+
+	private String toAttrSeries(String eqpId, String attr, Date start, Date end) {
+		return toSeries(machineAttrHistoryDao.findAttrInRange(eqpId, attr, start, end), start, "attr");
+	}
+
+	private String toSeries(List<MachineAttrHistory> list, Date windowStart, String type) {
+		String[] slots = emptySlots();
+		if (list == null || list.isEmpty()) {
+			return join(slots);
+		}
+		for (MachineAttrHistory row : list) {
+			if (row == null || row.getEventTime() == null) {
+				continue;
+			}
+			int idx = secIndex(row.getEventTime(), windowStart);
+			if (idx < 0 || idx >= POINT_COUNT) {
+				continue;
+			}
+			String val;
+			if ("cru".equals(type)) {
+				val = row.getCruTemp();
+			} else if ("alu".equals(type)) {
+				val = row.getAluTemp();
+			} else if ("ele".equals(type)) {
+				val = row.getEleConsume();
+			} else if ("theory".equals(type)) {
+				val = row.getTheoryPressure();
+			} else if ("real".equals(type)) {
+				val = row.getRealPressure();
+			} else if ("level".equals(type)) {
+				val = row.getPressureLevel();
+			} else {
+				val = row.getVal();
+			}
+			slots[idx] = val == null ? "" : String.valueOf(val);
+		}
+		return join(slots);
+	}
+
+	private String toMouldSeries(List<MachineAttrHistory> list, Date windowStart) {
+		String[] slots = emptySlots();
+		if (list == null || list.isEmpty()) {
+			return join(slots);
+		}
+		Map<Integer, LinkedHashMap<String, String>> bySec = new LinkedHashMap<>();
+		for (MachineAttrHistory row : list) {
+			if (row == null || row.getEventTime() == null) {
+				continue;
+			}
+			int idx = secIndex(row.getEventTime(), windowStart);
+			if (idx < 0 || idx >= POINT_COUNT) {
+				continue;
+			}
+			LinkedHashMap<String, String> parts = bySec.get(idx);
+			if (parts == null) {
+				parts = new LinkedHashMap<>();
+				bySec.put(idx, parts);
+			}
+			String mouldId = row.getMouldInfo();
+			if (StringUtils.isBlank(mouldId)) {
+				continue;
+			}
+			parts.put(mouldId, row.getVal() == null ? "" : String.valueOf(row.getVal()));
+		}
+		for (Map.Entry<Integer, LinkedHashMap<String, String>> e : bySec.entrySet()) {
+			StringBuilder sb = new StringBuilder();
+			for (Map.Entry<String, String> p : e.getValue().entrySet()) {
+				if (sb.length() > 0) {
+					sb.append(',');
+				}
+				sb.append(p.getKey()).append(':').append(p.getValue());
+			}
+			slots[e.getKey()] = sb.toString();
+		}
+		return join(slots);
+	}
+
+	private static String[] emptySlots() {
+		String[] slots = new String[POINT_COUNT];
+		for (int i = 0; i < POINT_COUNT; i++) {
+			slots[i] = "";
+		}
+		return slots;
+	}
+
+	private static String join(String[] slots) {
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0; i < slots.length; i++) {
+			if (i > 0) {
+				sb.append('#');
+			}
+			sb.append(slots[i] == null ? "" : slots[i]);
+		}
+		return sb.toString();
+	}
+
+	private static int secIndex(Date eventTime, Date windowStart) {
+		long ms = eventTime.getTime() - windowStart.getTime();
+		if (ms < 0) {
+			return -1;
+		}
+		return (int) (ms / 1000L);
+	}
+
+	private static Date floorTo10Minutes(Date date) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		int minute = cal.get(Calendar.MINUTE);
+		cal.set(Calendar.MINUTE, minute - (minute % 10));
+		return cal.getTime();
+	}
+
+	private static Date addMinutes(Date date, int minutes) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		cal.add(Calendar.MINUTE, minutes);
+		return cal.getTime();
+	}
+
+	private static String format(Date date) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		return String.format("%04d-%02d-%02d %02d:%02d:%02d",
+				cal.get(Calendar.YEAR),
+				cal.get(Calendar.MONTH) + 1,
+				cal.get(Calendar.DAY_OF_MONTH),
+				cal.get(Calendar.HOUR_OF_DAY),
+				cal.get(Calendar.MINUTE),
+				cal.get(Calendar.SECOND));
+	}
+}

+ 25 - 0
src/main/java/com/jeesite/modules/tianHong/dao/MachineAttrHistoryDao.java

@@ -44,4 +44,29 @@ public interface MachineAttrHistoryDao extends CrudDao<MachineAttrHistory> {
 	 */
 	List<MachineAttrHistory> findAttrList(MachineAttrHistory machineAttrHistory);
 
+	/** 10分钟备份:时间窗内炉膛温度 */
+	List<MachineAttrHistory> findCruInRange(@Param("eqpId") String eqpId,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
+	/** 10分钟备份:时间窗内铝水温度 */
+	List<MachineAttrHistory> findAluInRange(@Param("eqpId") String eqpId,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
+	/** 10分钟备份:时间窗内模具温度 */
+	List<MachineAttrHistory> findMouldInRange(@Param("eqpId") String eqpId,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
+	/** 10分钟备份:时间窗内压力 */
+	List<MachineAttrHistory> findPressureInRange(@Param("eqpId") String eqpId,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
+	/** 10分钟备份:时间窗内电量 */
+	List<MachineAttrHistory> findEleInRange(@Param("eqpId") String eqpId,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
+	/** 10分钟备份:时间窗内指定属性 */
+	List<MachineAttrHistory> findAttrInRange(@Param("eqpId") String eqpId,
+			@Param("attr") String attr,
+			@Param("beginTime") Date beginTime, @Param("endTime") Date endTime);
+
 }

+ 29 - 0
src/main/resources/db/create/mysql/tianhong_backup.sql

@@ -0,0 +1,29 @@
+-- mes_cloud_ljr.tianhong_backup
+-- Window: [window_start, window_end) e.g. 14:00:00 ~ 14:10:00
+-- Curves: value#value, 600 slots (1s)
+
+CREATE TABLE IF NOT EXISTS `tianhong_backup` (
+  `id` BIGINT NOT NULL AUTO_INCREMENT,
+  `eqp_id` VARCHAR(40) NOT NULL,
+  `window_start` DATETIME NOT NULL,
+  `window_end` DATETIME NOT NULL,
+  `cru_temp` MEDIUMTEXT,
+  `alu_temp` MEDIUMTEXT,
+  `mould_info` MEDIUMTEXT,
+  `theory_pressure` MEDIUMTEXT,
+  `real_pressure` MEDIUMTEXT,
+  `pressure_level` MEDIUMTEXT,
+  `ele_consume` MEDIUMTEXT,
+  `alu_val` MEDIUMTEXT,
+  `pressurize_time` MEDIUMTEXT,
+  `cooling_time` MEDIUMTEXT,
+  `pre_pres` MEDIUMTEXT,
+  `hold_pressure` MEDIUMTEXT,
+  `mold_filling_pre` MEDIUMTEXT,
+  `point_count` INT DEFAULT NULL,
+  `create_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `update_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_eqp_window` (`eqp_id`, `window_start`),
+  KEY `idx_window` (`window_start`, `window_end`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

+ 56 - 0
src/main/resources/mappings/modules/tianHong/MachineAttrHistoryDao.xml

@@ -124,4 +124,60 @@
 		ORDER BY attr
 	</select>
 
+	<select id="findCruInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT Value AS "cruTemp", EventTime AS "eventTime"
+		FROM crutemphistory
+		WHERE EQP_ID = #{eqpId}
+		  AND EventTime &gt;= #{beginTime}
+		  AND EventTime &lt; #{endTime}
+		ORDER BY EventTime
+	</select>
+
+	<select id="findAluInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT Value AS "aluTemp", EventTime AS "eventTime"
+		FROM alutemphistory
+		WHERE EQP_ID = #{eqpId}
+		  AND EventTime &gt;= #{beginTime}
+		  AND EventTime &lt; #{endTime}
+		ORDER BY EventTime
+	</select>
+
+	<select id="findMouldInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT MouldID AS "mouldInfo", Value AS "val", EventTime AS "eventTime"
+		FROM mouldtemphistory
+		WHERE EQP_ID = #{eqpId}
+		  AND EventTime &gt;= #{beginTime}
+		  AND EventTime &lt; #{endTime}
+		ORDER BY EventTime, MouldID
+	</select>
+
+	<select id="findPressureInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT TheoryValue AS "theoryPressure", RealValue AS "realPressure",
+			LevelID AS "pressureLevel", EventTime AS "eventTime"
+		FROM pressurehistory
+		WHERE EQP_ID = #{eqpId}
+		  AND EventTime &gt;= #{beginTime}
+		  AND EventTime &lt; #{endTime}
+		ORDER BY EventTime
+	</select>
+
+	<select id="findEleInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT Value AS "eleConsume", EventTime AS "eventTime"
+		FROM EleConsumeHistory
+		WHERE EQP_ID = #{eqpId}
+		  AND EventTime &gt;= #{beginTime}
+		  AND EventTime &lt; #{endTime}
+		ORDER BY EventTime
+	</select>
+
+	<select id="findAttrInRange" resultType="com.jeesite.modules.tianHong.entity.MachineAttrHistory">
+		SELECT attr AS "attr", val AS "val", event_time AS "eventTime"
+		FROM machine_attr_history
+		WHERE eqp_id = #{eqpId}
+		  AND attr = #{attr}
+		  AND event_time &gt;= #{beginTime}
+		  AND event_time &lt; #{endTime}
+		ORDER BY event_time
+	</select>
+
 </mapper>