BDB je二级索引操作

本文介绍了一个使用Berkeley DB (BDB) 创建和使用多个二级索引的示例程序。通过示例展示了如何定义不同的二级索引并进行查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BDB是使用k-v存储的,默认就是一个key对应一个value,也就是说以key为索引。但是BDB是支持二级索引的,即Secondary Database,这个在官方文档有。不过它没提到的是,BDB支持多个二级索引。

下面的代码,演示了如何创建多个二级索引,插入数据,然后通过二级索引查询数据。

/**
 * @author wange
 */

import com.sleepycat.je.*;

import java.io.File;

public class SimpleSecIndex {
    private static final String dataPath = "~/data/";
    private static final String mainDbName = "mainDB";
    public static final String secDbName1 = "secDB1";
    public static final String secDbName2 = "secDB2";
    public static final String UTF8 = "UTF-8";

    private Database mainDb;
    private SecondaryDatabase secDb1, secDb2;
    private Environment dbEnv;


    /**
     * 写数据,最终的数据格式如下:
     * 其中1,2,3为primary index,即mainDb的key值。
     * 并且有两个二级索引,一个以name为key,另一个以no为key,它们指向的是一级索引的key值。
     * <p/>
     * data:
     * {
     * 1, name1, no1, birthday1;
     * 2, name2, no2, birthday2;
     * 3, name3, no3, birthday3;
     * ...
     * }
     * <p/>
     * primary index:  1,2,3...
     * sec index1:     name1-->1, name2-->2, ...
     * sec index2:     no1-->1, no2-->2, ...
     */
    public void writeData() {
        openDBs();
        try {

            for (int i = 0; i < 100; i++) {
                String k = i + "";
                DatabaseEntry key = createKeyEntry(k);
                DatabaseEntry value = createValueEntry(k);
                //不需要调用secDb1和secDb2的put方法,会自动创建索引
                mainDb.put(null, key, value);
            }
            dbEnv.sync();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            closeDBs();
        }
        System.out.println("Write data OK");
    }

    /**
     * 读数据,分别通过两个索引来查询
     */
    public void queryData() {
        openDBs();

        DatabaseEntry v1 = queryEntry("name50", secDb1);
        System.out.println(entryToString(v1));

        v1 = queryEntry("no55", secDb2);
        System.out.println(entryToString(v1));

        closeDBs();
    }

    /**
     * join查询,注意join cursor的多个索引条件之间,是与的关系而不是或,即最后join的时候必须都满足
     */
    public void jointQueryData() {
        openDBs();

        String index1 = "name30";
        String index2 = "no30"; //这时会返回一条记录,如果改成no45,则返回纪录为空
        Cursor cursor1 = null, cursor2 = null;
        JoinCursor joinCursor = null;
        try {
            cursor1 = secDb1.openCursor(null, null);
            cursor2 = secDb2.openCursor(null, null);

            DatabaseEntry retKey = new DatabaseEntry();
            DatabaseEntry retValue = new DatabaseEntry();

            DatabaseEntry key1 = createKeyEntry(index1);
            DatabaseEntry key2 = createKeyEntry(index2);

            OperationStatus status1 = cursor1.getSearchKey(key1, retValue, LockMode.READ_UNCOMMITTED);
            OperationStatus status2 = cursor2.getSearchKey(key2, retValue, LockMode.READ_UNCOMMITTED);
            if (status1 == OperationStatus.SUCCESS && status2 == OperationStatus.SUCCESS) {
                joinCursor = mainDb.join(new Cursor[]{cursor1, cursor2}, null);
                while (joinCursor.getNext(retKey, retValue, LockMode.READ_UNCOMMITTED) == OperationStatus.SUCCESS) {
                    System.out.println(entryToString(retKey) + ":" + entryToString(retValue));
                }
            } else {
                System.out.println("[null]");
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (cursor1 != null) {
                cursor1.close();
            }
            if (cursor2 != null) {
                cursor2.close();
            }
            if (joinCursor != null) {
                joinCursor.close();
            }
            closeDBs();
        }
    }

    public void openDBs() {
        File file = new File(dataPath);
        dbEnv = new Environment(file, getEnvConfig());
        mainDb = dbEnv.openDatabase(null, mainDbName, getMainDbConfig());
        secDb1 = dbEnv.openSecondaryDatabase(null, secDbName1, mainDb, getSecDbConfig(new SecKeyCreator("name")));
        secDb2 = dbEnv.openSecondaryDatabase(null, secDbName2, mainDb, getSecDbConfig(new SecKeyCreator("no")));
    }

    public void closeDBs() {
        secDb1.close();
        secDb2.close();
        mainDb.close();
        dbEnv.close();
    }

    public DatabaseEntry queryEntry(String key, Database db) {
        DatabaseEntry keyEntry = createKeyEntry(key);
        DatabaseEntry valueEntry = new DatabaseEntry();

        OperationStatus status = db.get(null, keyEntry, valueEntry,
                LockMode.READ_UNCOMMITTED);
        if (status == OperationStatus.SUCCESS)
            return valueEntry;
        return null;
    }


    public DatabaseEntry createKeyEntry(String key) {
        DatabaseEntry entry = null;
        try {
            entry = new DatabaseEntry(key.getBytes("UTF-8"));
        } catch (Exception ex) {

        }
        return entry;
    }

    public DatabaseEntry createValueEntry(String key) {
        String data = "name" + key + "," + "no" + key + "," + "birthday" + key;
        DatabaseEntry entry = null;
        try {
            entry = new DatabaseEntry(data.getBytes(UTF8));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return entry;
    }


    public String entryToString(DatabaseEntry entry) {
        try {
            String ret = new String(entry.getData(), UTF8);
            return ret;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "[null]";
    }


    private EnvironmentConfig getEnvConfig() {
        EnvironmentConfig envConfig = new EnvironmentConfig();
        envConfig.setAllowCreate(true);
        envConfig.setReadOnly(false);
        envConfig.setTransactional(false);
        envConfig.setLocking(false);
        return envConfig;
    }

    private DatabaseConfig getMainDbConfig() {
        DatabaseConfig dbConfig = new DatabaseConfig();
        dbConfig.setAllowCreate(true);
        dbConfig.setTransactional(false);
        dbConfig.setReadOnly(false);
        dbConfig.setDeferredWrite(false);
        dbConfig.setSortedDuplicates(false);
        return dbConfig;
    }

    private SecondaryConfig getSecDbConfig(SecondaryKeyCreator keyCreator) {
        SecondaryConfig secConfig = new SecondaryConfig();
        secConfig.setKeyCreator(keyCreator);
        secConfig.setReadOnly(false);
        secConfig.setAllowCreate(true);
        //这个值为true时,通过二级索引进行查询,会直接把对应key的值取回来
        secConfig.setAllowPopulate(true);
        secConfig.setSortedDuplicates(true);
        return secConfig;
    }

    /**
     * 这个类告诉MainDB如何从它的key/value中创建出二级索引。在这个例子中,我们的值有三个字段name, no, birthday,
     * 二级索引为name, no这两个字段。我们只要能够拼出对应记录的这两个字段的值即可。
     * 这里没有使用TupleBinding。
     */
    class SecKeyCreator implements SecondaryKeyCreator {
        private String prefix;

        public SecKeyCreator(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public boolean createSecondaryKey(SecondaryDatabase secondary, DatabaseEntry key, DatabaseEntry data, DatabaseEntry result) {
            try {
                String k = prefix + new String(key.getData(), UTF8);
                result.setData(k.getBytes(UTF8));
            } catch (Exception ex) {
            }
            return true;
        }
    }

    public static void main(String[] args) {
        SimpleSecIndex instance = new SimpleSecIndex();
        instance.writeData();
        instance.queryData();
        instance.jointQueryData();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值