Недавно я был укушен ошибкой NoSQL — или, как мой коллега Марк Этвелл, придумал: «Сожги где»! движение. Хотя я не собираюсь в ближайшее время избегать дружеского «SELECT … WHERE» — или в обозримом будущем, мне все-таки удалось испачкать руки каким-нибудь кодом. В этой статье я делюсь знаниями о моих первых попытках в мире NoSQL.
В этой статье мы стремимся настроить и запустить базовое Java-приложение, способное взаимодействовать с MongoDB. Само по себе это не очень сложная задача, и, возможно, вы могли бы получить это менее чем за 10 минут. Нажмите здесь или нажмите здесь, или нажмите здесь , для некоторого превосходного материала. Однако я хотел продвинуться немного дальше.
Я хочу добавить поддержку ORM. Я выбрал Morphia для этой статьи. Я также хочу добавить шаблон DAO, модульное тестирование и ведение журнала. Короче говоря, я хочу, чтобы это выглядело «почти как» тот код, который большинство из нас написали бы для корпоративных приложений, используя, скажем, Java, Hibernate и Oracle. И мы постараемся сделать все это в течение 30 минут.
Я намерен заверить разработчиков Java + RDBMS в том, что Java + NoSQL не очень чужды. Это похожий код и его легко попробовать. Возможно, сейчас уместно добавить, что я не имею никакого отношения к NoSQL и не имею проблем с RDBMS. Я полагаю, что у них обоих есть свое собственное использование ( щелкните здесь для некоторого превосходного материала). Как технолог, мне просто нравится лучше знать свои инструменты, чтобы я мог отдать должное своей профессии. Эта статья направлена исключительно на то, чтобы помочь единомышленникам окунуться в NoSQL.
Хорошо, хватит разговоров. Давайте начнем. Вам понадобится несколько программ / инструментов, прежде чем вы будете следовать этой статье. Загрузите и установите сервер MongoDB, если вы этого еще не сделали. Я предполагаю, что у вас есть Java, немного Java IDE и инструмент для сборки и выпуска. Я использую jdk 7, Eclipse (STS) и Maven 3 для этой статьи.
Я начинаю с создания стандартного Java-приложения Vanilla с использованием Maven. Мне нравится использовать командный файл для этого.
Файл: codeRepo \ MavenCommands.bat
ECHO OFF REM ============================= REM Set the env. variables. REM ============================= SET PATH=%PATH%;C:\ProgramFiles\apache-maven-3.0.3\bin; SET JAVA_HOME=C:\ProgramFiles\Java\jdk1.7.0 REM ============================= REM Create a simple java application. REM ============================= call mvn archetype:create ^ -DarchetypeGroupId=org.apache.maven.archetypes ^ -DgroupId=org.academy ^ -DartifactId=dbLayer002 pause
Импортируйте его в Eclipse. Используйте Maven для компиляции и запуска, чтобы быть уверенным.
mvn -e clean install.
Это должно скомпилировать код и запустить тесты по умолчанию. Как только вы преодолели это препятствие, давайте теперь перейдем к некоторому кодированию. Давайте создадим объект Entity для начала. Я думаю, что класс Person с fname будет служить нашей цели. Я признаю, что это тривиально, но это делает работу для учебника.
Файл: /dbLayer002/src/main/java/org/academy/entity/Person.java
package org.academy.entity; public class Person { private String fname; [...] }
Я не упомянул геттеры и сеттеры для краткости.
Теперь давайте возьмем Java-драйвер MongoDB и подключим его к приложению. Мне нравится, когда Maven сделает это для меня. Очевидно, вы можете сделать это немного вручную. Твой выбор. Я просто ленивый.
Файл: /dbLayer002/pom.xml
[...] <!-- MongDB java driver to hook up to MongoDB server --> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.7.3</version> </dependency> [...]
Это позволит нам написать класс util для подключения к экземпляру сервера MongoDB. Я предполагаю, что на вашем компьютере запущен и работает сервер с настройками по умолчанию.
Файл: /dbLayer002/src/main/java/org/academy/util/MongoUtil.java
public class MongoUtil { private final static Logger logger = LoggerFactory .getLogger(MongoUtil.class); private static final int port = 27017; private static final String host = "localhost"; private static Mongo mongo = null; public static Mongo getMongo() { if (mongo == null) { try { mongo = new Mongo(host, port); logger.debug("New Mongo created with [" + host + "] and [" + port + "]"); } catch (UnknownHostException | MongoException e) { logger.error(e.getMessage()); } } return mongo; } }
Нам понадобится настроить регистратор в нашем приложении для этого класса для компиляции. Нажмите здесь для моей статьи о регистрации. Все, что нам нужно сделать, это подключить Maven с правильными зависимостями.
Файл: /dbLayer002/pom.xml
[...] <slf4j.version>1.6.1</slf4j.version> [...] <!-- Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> <scope>runtime</scope> </dependency>
А также, нам нужно будет указать, что именно регистрировать.
Файл: /dbLayer002/src/java/resources/log4j.properties
# Set root logger level to DEBUG and its only appender to A1. log4j.rootLogger=DEBUG, A1 # configure A1 to spit out data in console log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
На данный момент у вас уже есть класс Entity и служебный класс для подключения к базе данных. В идеале я хотел бы написать DAO и затем каким-то образом использовать ORM для объединения DAO с базой данных. Тем не менее, у Morphia есть отличная поддержка DAO. Также в нем есть несколько аннотаций для связи сущности с элементами базы данных. Итак, хотя мне бы хотелось, чтобы Entity и DAO были полностью независимы от ORM и базы данных, здесь это не так. Я знаю, что на первый взгляд кажется, что Morphia или MongoDB вынуждают меня отклониться от хорошей структуры кода, позвольте мне добавить, что это не хуже, чем у других ORM, например Hibernate с аннотациями также заставил бы меня сделать такой же компромисс.
Итак, давайте приведем Морфию на картинке. На сцену выходит наш всегда полезный инструмент, Maven. Немного здесь можно избежать заминки. Когда я писал этот документ, я не мог получить нужную версию Morphia в центральном хранилище Maven. Поэтому мне пришлось настроить Maven на использование репозитория Morphia. Надеюсь, это всего лишь временная ситуация.
Файл: /dbLayer002/pom.xml
[...] <!-- Required for Morphia --> <repositories> <repository> <id>Morphia repository</id> <url>http://morphia.googlecode.com/svn/mavenrepo/</url> </repository> </repositories> [...]
<!-- Morphia - ORM for MongoDB --> <dependency> <groupId>com.google.code.morphia</groupId> <artifactId>morphia</artifactId> <version>0.98</version> </dependency>
Как я упоминал выше, Morphia позволяет нам аннотировать класс Entity (так же, как аннотации Hibernate). Итак, вот как выглядит обновленный класс Entity.
Файл: /dbLayer002/src/main/java/org/academy/entity/Person.java
[...] @Entity public class Person { @Id private ObjectId id; [...]
И теперь мы можем также добавить слой DAO и опираться на BasicDAO, который предоставляет Morphia.
Файл: /dbLayer002/src/main/java/org/academy/dao/PersonDAO.java
public class PersonDAO extends BasicDAO<Person, ObjectId> { public PersonDAO(Mongo mongo, Morphia morphia, String dbName) { super(mongo, morphia, dbName); } [...]
Прелесть BasicDAO в том, что просто расширяя его, мой собственный класс DAO уже обладает достаточной функциональностью для выполнения основных операций CRUD , хотя я только что добавил конструктор. Не верь этому? Хорошо, давайте напишем тест для этого.
Файл: /dbLayer002/src/test/java/org/academy/dao/PersonDAOTest.java
public class PersonDAOTest { private final static Logger logger = LoggerFactory .getLogger(PersonDAOTest.class); private Mongo mongo; private Morphia morphia; private PersonDAO personDao; private final String dbname = "peopledb"; @Before public void initiate() { mongo = MongoUtil.getMongo(); morphia = new Morphia(); morphia.map(Person.class); personDao = new PersonDAO(mongo, morphia, dbname); } @Test public void test() { long counter = personDao.count(); logger.debug("The count is [" + counter + "]"); Person p = new Person(); p.setFname("Partha"); personDao.save(p); long newCounter = personDao.count(); logger.debug("The new count is [" + newCounter + "]"); assertTrue((counter + 1) == newCounter); [...]
Как вы уже могли заметить. Я использовал JUnit 4. Если бы вы следили за этой статьей до сих пор, у вас будет более ранняя версия JUnit в вашем проекте. Чтобы убедиться, что вы используете JUnit 4, вам просто нужно настроить Maven для использования этого, добавив правильную зависимость в pom.xml.
Файл: /dbLayer002/pom.xml
<!-- Unit test. --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency>
Тебе хорошо идти. Если вы запускаете тесты, они должны пройти. Конечно, вы можете / должны войти в вашу базу данных и убедиться, что данные действительно сохранены. Я отсылаю вас к документации MongoDB, которую я считаю вполне приличной.
И последнее, но не менее важное: позвольте мне заверить вас, что BasicDAO не имеет никаких ограничений. Я уверен, что пуритане отметят, что если моему классу DAO необходимо расширить BasicDAO, то это в любом случае является ограничением структуры исходного кода. В идеале не должно было быть необходимости. И я согласен с этим. Однако я также хочу показать, что для всех практических целей DAO у вас достаточно гибкости. Давайте продолжим и добавим в наш DAO собственный метод поиска, специфичный для этого объекта, то есть Person. Допустим, мы хотим иметь возможность поиска по имени и что мы хотим использовать для этого регулярное выражение. Вот как будет выглядеть код.
Файл: /dbLayer002/src/main/java/org/academy/dao/PersonDAO.java
public class PersonDAO extends BasicDAO<Person, ObjectId> { [...] public Iterator<Person> findByFname(String fname){ Pattern regExp = Pattern.compile(fname + ".*", Pattern.CASE_INSENSITIVE); return ds.find(entityClazz).filter("fname", regExp).iterator(); } [...] }
Важно еще раз подчеркнуть, что я только что добавил пользовательскую функцию поиска в свой DAO, добавив ровно три строки кода (четыре, если вы добавите последние скобки). В моих книгах это довольно гибко. Будучи верным моей неизменной любви к автоматизированному тестированию, давайте добавим быстрый тест, чтобы проверить эту функциональность, прежде чем мы закончим.
Файл: /dbLayer002/src/test/java/org/academy/dao/PersonDAOTest.java
[...] Iterator<Person> iteratorPerson = personDao.findByFname("Pa"); int personCounter = 0 ; while(iteratorPerson.hasNext()){ personCounter ++; logger.debug("["+personCounter+"]" + iteratorPerson.next().getFname()); } [...]
Прежде чем вы укажете, да, здесь нет assert (), так что это не настоящий тест. Позвольте мне заверить вас, что мой тестовый курс действительно завершен. Просто этот фрагмент здесь не имеет функции assert.
Итак, это все. Вы использовали Java для подключения к базе данных NoSQL, используя ORM, через уровень DAO (где вы использовали функциональные возможности ORM и также сделали некоторые дополнения). Вы также сделали правильное ведение журнала и модульное тестирование. Неплохо полчаса, а? Удачного кодирования.
Примечание: оригинальная статья доступна в блоге автора. Нажмите здесь .