Нет причин тормазить свое развитие.
Георгий Александров.
Здравствуйте друзья!!!Георгий Александров.
В этом посте я бы хотел вам рассказать про возможности использования memcachedb на java.
О memcachedb
Давайте начнем наш разговор с того, что разберемся, что же это за зверь такой memcachedb. В двух словах это такой вид субд, обращение к которой происходит через протокол memcached (интересная презентация на эту тему), а бэкэндом является BerkeleyDB. Более подробно можно прочитать здесь.
Установка и запуск
Ну что ж приступим к установке у себя на компьютере этой прелести. Сразу хочу оговориться, что устанавливать мы будем на Ubuntu, но на других платформах я думаю, никаких сложностей с установкой у вас не возникнет.
Для начала нам нужно установить libevent.
Теперь нам необходимо поставить BerkeleyDB. Исходники скачать можно здесь.sudo apt-get install libevent1 libevent-dev
А вот теперь можно качнуть и поставить memcachedb. Исходники скачать можно здесь.tar -xvf db-4.7.25.tar.gz
cd db-4.7.25/build_unix
../dist/configure
make
sudo make install
Ну вот мы все установили и теперь можем запустить.tar -xvf memcachedb-1.2.0.tar.gz
cd memcachedb-1.2.0
./configure
make
sudo make install
Java клиентmemcachedb -d -v -u root -f some.db -N -H ~/memcachedb
Как я уже говорил ранее, интерфейсом для работы является memcached. Существует несколько клиентов для работы с memcached. Полный список клиентов можно посмотреть здесь. Я выбрал spymemcached, поэтому дальнейшее повествование пойдет о нем.
Demo application
Наконец-то мы все скачали, установили, запустили и подключили. Теперь можем написать небольшое демонстрационное приложение. Наше приложение будет некое подобие тестовой системы. Оно будет задавать пользователю вопрос, ждать пока пользователь ответит на вопрос и сверять правильно ли ответил пользователь на поставленный вопрос. Так как приложение мы пишем для демонстрации работы с memcachedb то, особо сильной логикой перегружать его не будем.
Немного расскажу как у нас будут хранится данные так как memcachedb является бд key=value то мы будем использовать так называемые пространства имен т.е.[namespace]:[key]=[value].
Ну что ж вроде все обговарили, код с комментариями в судию :)
Ну вот вроде и все, ничего сложного казалось бы нет. Выше приведенный код демонстрирует основные операции для работы с memcachedb. НО! есть одно НО! это работа с memcachedb в многопоточной среде. Простейшая операция увеличения sequence для получения id новой записи, реализованная следующим образом:
/** * Copyright (c) 2009 alekseiko alekseiko@gmx.com */ package memcachedb.example.main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import net.spy.memcached.MemcachedClient; /** * This is main class for example. * * @author alekseiko * */ public class Main { // Customize for memcachedb private static MemcachedClient client; private static final String SERVER_NAME = "localhost"; private static final int SERVER_PORT = 21201; private static final int EXPIRED = 0; // Memcachedb namespace and key private static final String TASK_SEQUENCE = "taskSequence"; private static final String TASK_QUESTION = "task_question:"; private static final String TASK_ANSWERS = "task_answers:"; private static final String TASK_TRUE_ANSWER = "task_true_answer:"; // User command private static final String STOP_COMMAND = "stop"; private static final String NEXT_TASK_COMMAND = "n"; // Splitters private static final String ANSWER_SPLITTER = ","; private static final String ANSWER_NUMBER_SPLITTER = ") "; // Messages private static final String CONGRATULATION_MESSAGE = "Congratulation! " + "Enter 'n' for get next question"; private static final String QUESTIONS_IS_COMPLETE_MESSAGE = "Question is" + " complete."; private static final String DATA_IS_CORRUPT_MESSAGE = "Data is corrupt."; private static final String BAD_ANSWER = "Sorry you answer is incorrect. " + "Try again."; /** * General logic for work with memcachedb and user i/o. * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // Connect to memcachedb client = new MemcachedClient(new InetSocketAddress(SERVER_NAME, SERVER_PORT)); // Hardcode fill memcachedb of tasks. fillMemcachedbOfTask(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String msg = null; // Default currentTask=0 because task begin with 1 int currentTaskId = 0; // Get last sequence value int maxTaskId = (Integer) client.get(TASK_SEQUENCE); while(!STOP_COMMAND.equals(msg = br.readLine())) { if (NEXT_TASK_COMMAND.equals(msg)) { if (currentTaskId >= maxTaskId) { System.out.println(QUESTIONS_IS_COMPLETE_MESSAGE); break; } currentTaskId++; // Get task from memcachedb. String question = (String) client.get(TASK_QUESTION + currentTaskId); String answers = (String) client.get(TASK_ANSWERS + currentTaskId); if (question !=null && answers != null) { // Out question System.out.println(question); // Split answers String[] answerList = answers.split(ANSWER_SPLITTER); // Out answers for (int i = 0;i < answerList.length;i++) { System.out.println((i+1) + ANSWER_NUMBER_SPLITTER + answerList[i]); } } else { // Out error message if data in memcachedb is corrupt. System.out.println(DATA_IS_CORRUPT_MESSAGE); break; } } else { // Get true answer String trueAnswer = (String) client.get(TASK_TRUE_ANSWER + currentTaskId); if ((trueAnswer != null) && (trueAnswer.equals(msg))) { // Out congratulation message if answer is true. System.out.println(CONGRATULATION_MESSAGE); } else { // Out bad message if answer is bad. System.out.println(BAD_ANSWER); } } } // Shutdown client client.shutdown(); } private static void fillMemcachedbOfTask() { // Hardcode firs task // Set task question client.set(TASK_QUESTION + 1, EXPIRED, "What is your name?"); // Set task answers client.set(TASK_ANSWERS + 1, EXPIRED, "Aleksei,Petia,Katia,Sveta"); // Set true task client.set(TASK_TRUE_ANSWER + 1, EXPIRED, "Aleksei"); // Hardcode second task // Set task question client.set(TASK_QUESTION + 2, EXPIRED, "Do you speak english?"); // Set task answers client.set(TASK_ANSWERS + 2, EXPIRED, "yes,no"); // Set true task client.set(TASK_TRUE_ANSWER + 2, EXPIRED, "yes"); // Hardcode task sequence client.set(TASK_SEQUENCE, EXPIRED, 2); } }
может привести к коллизии.
int nextTaskId = (Integer) client.get(TASK_SEQUENCE); nextTaskId++; client.set(TASK_SEQUENCE, EXPIRED, nextTaskId);
Для того чтобы таких ситуаций не возникало существют incr/decr, инкримент и дикримент соответственно. Они увеличивают/уменьшают значение ключа и возвращают результат.
Что ж я вроде сказал все что хотел сказать.
Надеюсь мой небольшой очерк вам поможет...
Всем спасибо!
Интересные ссылки по теме:
Твиттер на основе Memcachedb и PHP
memcached на пальцах
Читать далее