Cập nhật field JOB_DATA kiểu BLOB của table JOB_DETAILS khi sử dụng Java Quartz Scheduler
Cập nhật field JOB_DATA kiểu BLOB của table JOB_DETAILS khi sử dụng Java Quartz Scheduler
Trong lúc fix 1 một bug liên quan đến Quartz mình đã gặp một tình huống là cần update field JOB_DATA kiều BLOB, dữ liệu chứa trong BLOB này là dạng binary của object trong Java, mình đã mất cả buổi để tìm kiếm cách lấy ra object này và update lại field này. Sao cả buổi tìm kiếm không có kết quả nên mình đã tự viết đoạn code Java để sửa lại object này. Thấy hữu ích nên mình viết bài này để chia sẻ lại cho bạn nào gặp trường hợp như mình.
Lấy dữ liệu từ database
Trên môi trường production thì mình không thể viết code để code lấy dữ liệu từ db prod được, mà mình phải viết câu select để lấy dữ liệu ra để convert. Mình dùng MySQL Workbench
select JOB_DATA
from scheduler_service.QRTZ_JOB_DETAILS
nhưng dữ liệu hiện ra chỉ là chữ BLOB, khi view thì nó là dạng binary vậy làm sao để lấy được bay giờ. Sau một hồi loay hoay thì mình việc chuyển nó về hex. Mình đã thay đổi câu SQL 1 chút.
select HEX(JOB_DATA)
from scheduler_service.QRTZ_JOB_DETAILS;
có chuỗi hex thì ta làm gì tiếp với nó bây giờ?
Convert dữ liệu từ database
Từ đoạn hex trên thì mình sẽ convert nó từ Hex về Object trong Java.
var jobData = hexStringToObject(originHex);
public static Object hexStringToObject(String hexString) throws IOException, ClassNotFoundException {
byte[] byteArray = hexStringToByteArray(hexString);
return deserialize(byteArray);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
private static Object deserialize(byte[] byteArray) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
ObjectInputStream ois = new ObjectInputStream(bais)) {
return ois.readObject();
}
}
Sau khi có được object Java thì ta cần biết kiểu của object này, nên mình đi kiểm tra kiểu của object này.
System.out.println("type: " + data.getClass().getName());
và ta có kết quả
org.quartz.JobDataMap
mình sẽ ép kiểu cho object java mình sửa lại đoạn code 1 chút.
var jobData = (JobDataMap)hexStringToObject(originHex);
sau khi in jobData ra mành hình ta có thông tin:
ObjectMapper objectMapper = new ObjectMapper();
System.out.println("Job Data Input: | " + objectMapper.writeValueAsString(data));
và kết quả
{"ITEM_ID":"b222dc19-2dcf-4017-86b0-9cc0786acf42","JOB_TYPE":"JOB_TYPE_DEMO"}
mình cần thay đổi ITEM_ID nên mình sẽ update nó
data.put("ITEM_ID", uuid);
Sau khi thay đổi object thì giờ mình cần parse nó về lại hex để insert database
String hexString = objectToHexString(data);
public static String objectToHexString(Object obj) throws IOException {
byte[] byteArray = serialize(obj);
return bytesToHex(byteArray);
}
private static byte[] serialize(Object obj) throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj);
return baos.toByteArray();
}
}
public static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = String.format("%02X", b);
hexString.append(hex);
}
return hexString.toString();
}
giờ ta đã có chuỗi hex chúng ta cần. Việc cuối cùng là update nó vào lại database thôi
UPDATE QRTZ_JOB_DETAILS
SET JOB_DATA = '<hex_string>'
WHERE id = '...'
Vậy là done task, Cảm ơn Anh/Chị/Em đã đọc bài. Mình mới tập tành viết nên câu văn không hay lắm, mình muốn chia sẻ những vấn đề mình gặp phải để giúp đỡ ai trong hoàn cảnh của mình, mong nhận được sự đóng góp từ mọi người, và cao nhân chỉ giáo thêm.
All rights reserved