🍃前言
本次开发目标
- 实现消息删除逻辑
也就是将Massage对象的isValid字段设置为0x0
🌲实现步骤
实现该逻辑我们可以分为以下6步
🚩检验参数的合法性
我们需要检查一下当前要写入的队列对应的文件是否存在.
不合法的话,抛出我们的自定义异常
🚩读取Message数据
我们要对Message对象进行修改,首先就需要将相应的Message读取出来
但是我们之前使用的FilelnputStream 和 FileOutputStream 都是从文件头读写的。
而我们此处需要的是,在文件的指定位置进行读写,随机访问
所以此处使用到的类为:RandomAccessFile
在该类中,我们可以使用以下方法进行读取
- read:读
- write:写
- seek:调整当前的文件光标(当前读写文件的位置)
seek可以使文件光标移动,read 和 write 本身也会引起光标移动
如此以来我们就可以进行读取了,我们创建一个byte类型的数组,数组大小为我们存储在内存中的message对象。
message.getOffsetEnd() - message.getOffsetBeg()
然后使用seek方法将光标调至 该message 的起始位置
然后进行读取
🚩二进制转为message
当前读出来的数据还是二进制的,我们要对它进行反序列转成Message对象
🚩isValid 设置为无效
这里只需要设置硬盘中的数据就好
🚩写入文件
该操作分为三步
- 将新设置好的对象序列化
- 调整光标至该消息的起始位置
- 写入数据
🚩更新统计文件
不要忘了, 更新统计文件!! 把一个消息设为无效了, 此时有效消息个数就需要 - 1
🚩特别注意
我们这个操作依旧是存在线程安全问题的,所以依旧需要进行加锁操作
🚩完整代码
// 这里的删除是逻辑删除, 也就是把硬盘上存储的这个数据里面的那个 isValid 属性, 设置成 0 // 1. 先把文件中的这一段数据, 读出来, 还原回 Message 对象; // 2. 把 isValid 改成 0; // 3. 把上述数据重新写回到文件. // 此处这个参数中的 message 对象, 必须得包含有效的 offsetBeg 和 offsetEnd public void deleteMessage(MSGQueue queue, Message message) throws IOException, ClassNotFoundException, MqException { // 1. 检查一下当前要写入的队列对应的文件是否存在. if (!checkFilesExits(queue.getName())) { throw new MqException("[MessageFileManager] 队列对应的文件不存在! queueName=" + queue.getName()); } synchronized (queue) { try (RandomAccessFile randomAccessFile = new RandomAccessFile(getQueueDataPath(queue.getName()), "rw")) { // 2. 从文件中读取对应的 Message 数据. byte[] bufferSrc = new byte[(int) (message.getOffsetEnd() - message.getOffsetBeg())]; randomAccessFile.seek(message.getOffsetBeg()); randomAccessFile.read(bufferSrc); // 3. 把当前读出来的二进制数据, 转换回成 Message 对象 Message diskMessage = (Message) BinaryTool.fromBytes(bufferSrc); // 4. 把 isValid 设置为无效. diskMessage.setIsValid((byte) 0x0); // 此处不需要给参数的这个 message 的 isValid 设为 0, 因为这个参数代表的是内存中管理的 Message 对象 // 而这个对象马上也要被从内存中销毁了. // 5. 重新写入文件 byte[] bufferDest = BinaryTool.toBytes(diskMessage); // 虽然上面已经 seek 过了, 但是上面 seek 完了之后, 进行了读操作, 这一读, 就导致, 文件光标往后移动, 移动到 // 下一个消息的位置了. 因此要想让接下来的写入, 能够刚好写回到之前的位置, 就需要重新调整文件光标. randomAccessFile.seek(message.getOffsetBeg()); randomAccessFile.write(bufferDest); // 通过上述这通折腾, 对于文件来说, 只是有一个字节发生改变而已了~~ } // 6.不要忘了, 更新统计文件!! 把一个消息设为无效了, 此时有效消息个数就需要 - 1 Stat stat = readStat(queue.getName()); if (stat.validCount > 0) { stat.validCount -= 1; } writeStat(queue.getName(), stat); } }
⭕总结
关于《【消息队列开发】 实现消息删除逻辑》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下