首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MapDB 同步读写示例

MapDB 同步读写示例

作者头像
凡梦星尘
发布2024-11-20 17:21:06
发布2024-11-20 17:21:06
3260
举报
文章被收录于专栏:Hugo博客Hugo博客

MapDB 是一个快速、易用的嵌入式Java数据库引擎. 最主要的特点之一就是支持磁盘存储,直接把内存中的Hash Map同步写入到磁盘. 另外特别惊喜的是它支持ACID事务,MVCC隔离, 且有全职的开发者支持.

看完官方的文档与示例后,基本上可以确定它符合业务场景的使用要求.另外发现官方正在重构3.x的版本, 但应该不会这么快发布吧.用google搜索了下关于MapDB的使用案例, 也不是很多. 可能是本来官方的文档就齐全有关吧,API也不复杂,跟着官方的文档走一遍就可以上手了.

动手测试了简单的示例后, 突然冒出一个疑问, 如何实现同时操作磁盘上的一个数据库, 以及同一个HashMap呢? 这里需要明白的, MapDB存储到磁盘上的数据库文件,并非只是存放了一个HashMap, 这有点类似数据库里可以有多张表的概念相同. 那么数据库是可以支持多连接的, MapDB是否也同样支持呢?(理想确实很丰满,但现实太骨感了!)

初步检验的结果是, MapDB并不支持同时访问磁盘上的同一文件. 那么也就是只能创建一个长连接, 直到业务功能处理完成再关闭它. 幸运的是它支持对已经存在或是运行中的同一个HashMap进行读写操作. 下面来看看简单的示例代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

import org.mapdb.BTreeMap; import org.mapdb.DB; import org.mapdb.DBMaker; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import java.io.File; import java.util.Map; import java.util.Random; import java.util.SortedMap; import static org.testng.Assert.*; /** * MapDB 测试 * * @author 凡梦星尘(elkan1788@gmail.com) * @since 2016.1.19 */ public class MapDBTest { private DB diskDB; Map<Integer, String> data; @BeforeTest public void init() { // 文件名字可以自己定义 File dbFile = new File("D:/mapdb.data"); // DB有且只打开一次连接 diskDB = DBMaker.fileDB(dbFile) // 很是好奇,关闭锁定,还是不支持多事务访问同一个数据库文件 .fileLockDisable() // 最好开启,在程度异常或JVM关闭可正常关闭数据库 // 有过一次无法访问未关闭数据库文件的异常 .closeOnJvmShutdown() // 如果不需要回滚的可以关闭,提高读写效率 .transactionDisable() // 这里测试所没不保留磁盘文件 .deleteFilesAfterClose() // 这里没有找到读取的API,或者就是不支持多连接的吧 .make(); } @AfterTest public void destroy() { assertTrue(!data.isEmpty()); // 本应该是99才对,但会合并内存中其它数据 Map<Integer, String> temp = diskDB.treeMap("sort_mapdb"); assertEquals(temp.size(), 100); // 这里需要注意下,有可能make成功的数据库也是关闭的 // 如果不做检查的话,可能抛出:IllegalAccessError("DB was already closed") if (diskDB.isClosed()) { diskDB.isClosed(); } } @Test(invocationCount = 10) public void testSyncWrite() throws Exception { // 支持多种类型Map,如B+ tree, sort等等 // 但value貌似支持引用类型, 不支持Object, 可能是 // 跟序列化到磁盘存储有关 data = diskDB.treeMapCreate("nice_mapdb") // 开启快速计数器 .counterEnable() // 这步很关键,如果不带get,那么就只是make,无法支持多连接 .makeOrGet(); int len = 99; int ran = new Random().nextInt(100)+1; while (--len >= 0) { data.put(len * ran, "value-"+len * ran); } assertFalse(data.isEmpty()); } @Test(invocationCount = 10) public void testReadAndDel() throws Exception { data = diskDB.treeMapCreate("nice_mapdb") .counterEnable() .makeOrGet(); if (!data.isEmpty()) { for (Integer key : data.keySet()) { if (key % 2 == 0 || key % 5 == 0) { data.remove(key); } } assertTrue(data.size() > 0); } } @Test public void testOtherMap() throws Exception { SortedMap<Integer, String> data = diskDB.treeMapCreate("sort_mapdb") .counterEnable() .makeOrGet(); int len = 99; while (--len >= 0) { data.put(len, "sorted-"+len); } assertNotNull(data); // 创建另一个map BTreeMap<Integer, String> btree = diskDB.treeMapCreate("sort_mapdb2") .counterEnable() .makeOrGet(); // 很是奇怪, 为何这里的name没有效果, 会自动合并到同时一时内存所有treeMap中 SortedMap<Integer, String> tree = diskDB.treeMap("sort_mapdb1"); tree.put(100, "sorted-100"); btree.put(100, "sorted-101"); assertEquals(tree.get(100), "sorted-100"); assertEquals(data.get(100), "sorted-100"); } }

在这里没有详细的探讨关于MapDB是如何实现与磁盘持久化同步, 直接使用官方默认的值, 当然你也可以自己配置读写同步的心跳时间间隔. 在测试的过程观察发现, MapDB在创建磁盘的数据库文件时, 初始化大小写为2MB, 然后在同步内存数据时, 会先产生出一个临时文件, 当这个临时文件达到一定大小时就会合并到主体数据库文件. 至于其它的功能和代码中的疑问, 有待继续观察, 欢迎共同交流.

参考资料:

  • MapDB 官网
  • 官方示例
  • MapDB实现分析
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档