Рубрики
Без рубрики

Руководство по доступу к базам данных на Java

Вы можете использовать это руководство, чтобы найти, понять и выбрать правильную библиотеку Java для доступа к базе данных… С тегами java, база данных, jdbc, режим гибернации.

Вы можете использовать это руководство, чтобы обнаружить, понять и выбрать правильную библиотеку Java для доступа к базе данных, такой как MySQL, Postgres, Oracle – или любой другой.

Прочитайте это руководство, чтобы понять, какая библиотека баз данных имеет смысл для вашего проекта и команды разработчиков.

Вступление

Всякий раз, когда вы хотите подключиться к базе данных с помощью приложения Java (сервер/рабочий стол), появляются три вопроса:

  • Вы подходите к своему приложению с точки зрения Java-в первую очередь или с точки зрения базы данных? Что из двух вы хотите написать первым или уже существует?

  • Как вы выполняете инструкции SQL, от небольших операций CRUD (таких как старая добрая вставка в ) до сложных запросов отчетов SQL (аналитических функций)?

  • Как легко вы можете перейти от (читайте: карта между ) Объект Java в таблице базы данных? Из таблицы базы данных в объект Java?

Итак, представьте себе класс Java, подобный этому:

    public class User {

        private Integer id;

        private String firstName;

        private String lastName;

        // Constructor/Getters/Setters....

    }

Теперь представьте, что у вас есть, скажем, три таких пользователя, и вы хотите сохранить их в таблице базы данных (” пользователи “), которая выглядит следующим образом:

идентификатор первое имя фамилия и имя
1 ханси Хубер
2 максимум мутцке
3 дональд козырь

Оказывается, в яванской стране есть различные способы сделать это, можно даже сказать, слишком много. Следовательно, давайте достанем мачете и прорежем дерево различными доступными вам вариантами.

Однако, как всегда, очень важно понимать основы, так как любой другой вариант основывается НА этих основах. Поэтому убедитесь, что не пропустите следующий раздел, если вы не уверены в некоторых из упомянутых концепций.

Базовый Доступ К Базе Данных Java

Драйверы JDBC

Для подключения к вашей базе данных, будь то MySQL или Н2 , вам нужен драйвер, драйвер JDBC .

Драйверы JDBC выполняют значительный объем работы, от основ открытия соединений с базой данных до более продвинутых функций, таких как предоставление возможности получать события из базы данных (Oracle).

Поэтому независимо от того, какую библиотеку баз данных Java вы собираетесь использовать в своем проекте, вам нужно будет перейти на веб-сайт базы данных или в репозиторий maven , получить последний драйвер JDBC и добавить его в свой проект.

Это буквально все, что вам нужно для начала. В случае, если вы хотите подключиться к “тестовой” базе данных MySQL, установленной на вашем локальном компьютере, вы должны написать следующий код:

(Совет родителям: Не копируйте этот код вслепую).

    try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test")) {
        assertTrue(conn.isValid(1000));
        // Do something with the Connection
    }

Пулы соединений

Открытие и закрытие соединений с базой данных занимает некоторое время. Особенно в веб-приложениях вы не хотите открывать новое подключение к базе данных для каждого пользователя, скорее вы хотите иметь небольшой пул подключений , которые всегда открыты и которые являются общими для пользователей. Вот для чего нужны пулы соединений.

Некоторые драйверы JDBC, такие как Oracle, поставляются с собственным пулом соединений ( UCP ). Для других баз данных вам необходимо самостоятельно загрузить пул соединений, и снова вы столкнетесь с множеством опций в Java land.

Те, которые вы найдете во многих (более старых) приложениях, – это Apache Commons DBCP и C3P0 .

К сожалению, вы также часто обнаружите, что они неправильно настроены, потому что им не хватает правильных, разумных значений по умолчанию, а также у них проблемы с производительностью и обработкой ошибок (см., Например, база данных отключена ).

В общем, поэтому я бы рекомендовал новым проектам использовать один из этих двух новых пулов соединений:

ХикариКП или Вибур-dbcp . Они оба надежны, производительность обеспечивает разумные значения по умолчанию и другие приятные функции удобства. Кроме того, для достижения максимальной производительности обязательно ознакомьтесь с документацией для конкретной базы данных для любого из этих двух.

Независимо от того, какой из вариантов вы выберете, вы затем в своем коде не будете самостоятельно открывать соединения через DriverManager, а скорее попросите пул соединений (источник данных) предоставить вам одно из своих подключений, например:

(Совет родителям: Не копируйте этот код вслепую).

    // in the case of using Hikari Connection Pool
    DataSource ds = new HikariDataSource(config);
    try (Connection connection = ds.getConnection()) {
        // use the connection
    }

Низкоуровневый доступ к базе данных (JDBC)

Самый низкоуровневый способ доступа к базам данных на Java – это API JDBC ( Подключение к базе данных Java ). JDBC поставляется с каждым JDK, и для его использования вам не нужны никакие дополнительные библиотеки. И следует также отметить, что каждая другая библиотека баз данных Java строится поверх JDBC.

приступая к работе

Как только у вас есть открытое соединение с базой данных (см. Выше), вы можете выполнять инструкции SQL через это соединение, как, например, с помощью консоли MySQL или SQLDeveloper Oracle.

Но простой JDBC немного громоздок в использовании и не очень помогает при преобразовании объектов Java в указанный SQL. На самом деле, все это остается делать самому. Давайте посмотрим, как выглядит базовая инструкция SQL Insert с простым JDBC:

(Совет родителям: Не копируйте этот код вслепую).

    public void insertWithJdbc() {
        User user = ... ;
        DataSource ds = ...;

        try (Connection conn = ds.getConnection()) {

            conn.setAutoCommit(false); // starts a new database transaction
            PreparedStatement statement = conn.prepareStatement("insert into users (first_name, last_name) values (?,?)");
            statement.setString(1, user.getFirstName());
            statement.setString(2, user.getLastName());
            statement.executeUpdate();

            // TODO insert some more users...
            conn.commit(); // commits the database transaction

        } catch (SQLException e) {
            // TODO print out error
            // TODO rollback transaction
        }
    }

Как вы можете видеть, то, что вам нужно сделать, это:

  • Откройте подключение к базе данных

  • Запустите транзакцию базы данных

  • Создайте подготовленное утверждение, которое представляет вашу вставку SQL и содержит некоторые заполнители

  • Заполните эти заполнители (несколько раз)

  • Наконец, зафиксируйте транзакцию

Обработка ошибок и Очистка ресурсов

Но это только половина истории. Всякий раз, когда происходит исключение SQLException, вы знаете, что что-то не так, но вы не знаете, что было или что не было совершено. И поскольку вы не знаете, вам нужно обязательно вручную откатить транзакцию.

Кроме того, поскольку вы хороший разработчик, вам также следует убедиться, что вы закрыли PreparedStatement и/или соединение явно, вместо того, чтобы надеяться, что оно будет закрыто автоматически (зависит от реализации драйвера JDBC) позже в вашем коде – и освободить любые ресурсы базы данных вместе с этим.

К счастью, это стало намного проще с внедрением Java 7 попробуйте с ресурсами .

Поэкспериментируйте немного сами с откатом соединения, используя приведенный выше пример кода. Также поэкспериментируйте с закрытием соединения и утверждений. Если вы немного заблудились, прочитайте соответствующую документацию Oracle .

Посмотрите, как будет выглядеть приведенный выше пример в “правильном” коде Java:

(Совет родителям: Не копируйте этот код вслепую).

    public void insertWithJDBCSafelyUpToJava7() {
        User user = new User();

        Connection conn = null;
        PreparedStatement statement = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost/test");
            conn.setAutoCommit(false); // starts a new database transaction
            statement = conn.prepareStatement("insert into users (first_name, last_name) values (?,?)");
            statement.setString(1, user.getFirstName());
            statement.setString(2, user.getLastName());
            statement.executeUpdate();
            conn.commit(); // commits the database transaction
        } catch (SQLException e) {
            // TODO do some application error handling here
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    // nothing you can really do here, apart from logging the error
                }
            }
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    // nothing you can really do here, apart from logging the error
                }
            }

            if (conn  != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // nothing you can really do here, apart from logging the error
                }
            }
        }
    }


    public void insertWithJDBCSafelyFromJava7Onwards() {
      User user = new User();
      try (Connection cxn = DriverManager.getConnection("jdbc:mysql://localhost/test");
          PreparedStatement stmt = cxn.prepareStatement("insert into users (first_name, last_name) values (?,?)")) {
        try {
          cxn.setAutoCommit(false); // starts a new database transaction
          stmt.setString(1, user.getFirstName());
          stmt.setString(2, user.getLastName());
          stmt.executeUpdate();
          cxn.commit(); // commits the database transaction
        } catch (SQLException e) {
          // TODO do some application error handling here
          try {
            cxn.rollback();
          } catch (SQLException ex) {
            // nothing you can really do here, apart from logging the error
          }
        }
      }
    }

Как вы можете видеть, начиная с Java 7, автоматическое закрытие соединений и операторов значительно упрощает очистку. Если вам не повезло быть на Android или Java 6 или ниже, вы можете использовать Гуава ближе к достижению кода, почти такого же чистого в отношении управления ресурсами.

Мы еще не говорили о выборе данных из таблиц. Давайте взглянем на это:

(Совет родителям: Не копируйте этот код вслепую).

    public void selectWithJdbc() {

        // check out the other examples above to understand where the statement variable comes from
        ResultSet resultSet = statement.executeQuery("select * from users");

        while (resultSet.next()) {
            String firstName = rs.getString("first_name");
            String lastName = rs.getString("last_name");

            System.out.println("first name : " + firstName);
            System.out.println("last name : " + lastName);
        }

    }

Таким образом, основной вывод заключается в том, что при использовании JDBC вы в основном работаете с голым металлом.

У вас есть вся мощь SQL под рукой, но вам нужно убедиться, что вы каким-то образом конвертируете туда и обратно между вашими объектами Java и кодом SQL самостоятельно. Кроме того, вам необходимо убедиться, что вы правильно поддерживаете и закрываете свои подключения/инструкции к базе данных.

Вот где появляются удобные библиотеки, такие как Spring (с его JdbcTemplate ), и мы рассмотрим это в следующем разделе.

Кроме того, прямое использование JDBC является вполне допустимым вариантом использования, и особенно новичкам следует ознакомиться с концепциями JDBC, прежде чем погружаться прямо в более тяжелые библиотеки, такие как Hibernate.

Если вы хотите практиковать основы баз данных Java

Я написал небольшую книгу, полную упражнений и примеров кода о том, как максимально упростить доступ к JDBC. Проверять Соединения и транзакции с Базой данных Java .

Первые библиотеки Java

Разработчикам Java обычно удобнее писать классы Java, чем писать SQL. Следовательно, многие (новые) проекты написаны с использованием подхода, основанного на Java, что означает, что вы создаете свой класс Java до создания соответствующей таблицы базы данных.

Затем у вас остается вопрос: как вы сопоставляете свои классы Java с указанными таблицами? Одним из решений является использование так называемых ORM, библиотек для объектно-реляционного отображения.

Зимовать

Одной из очень популярных библиотек, которая поможет вам в этом, является Hibernate , которая существует с 2001 года. Давайте сразу погрузимся (и, если вам нравятся видео, взгляните на эти короткие и практичные скринкасты , которые иллюстрируют все следующие концепции в реальном сценарии):

Представьте, что у вас есть следующая таблица, которая в основном является той же таблицей, которую вы использовали в разделе простого JDBC.

    create table users (
        id integer not null,
        first_name varchar(255),
        last_name varchar(255),
        primary key (id)
    )

и следующий соответствующий класс Java:

    public class User {

        private Integer id;

        private String firstName;

        private String lastName;

        //Getters and setters are omitted for brevity
    }

Теперь, чтобы начать, вам, очевидно, нужно добавить библиотеки гибернации в свой проект. Затем создайте файл конфигурации для гибернации hibernate.cfg.xml чтобы создать так называемый SessionFactory , или создайте этот SessionFactory непосредственно в своем Java-коде.

Что такое сессионный завод? Зачем он мне нужен?

SessionFactory в основном представляет сопоставление между вашими классами Java и таблицами базы данных (подробнее об этом через секунду). Кроме того, SessionFactory производит, кто бы мог подумать, Сеансы. Сеанс – это в основном соединение с базой данных (или, более конкретно, оболочка соединения JDBC), с дополнительными преимуществами сверху.

Но сначала давайте посмотрим на карту. Очевидно, что Hibernate не имеет возможности узнать, какие из ваших классов должны быть сопоставлены с таблицами базы данных из коробки. Следовательно, вам нужно сопоставление. Традиционно вы выполняли сопоставление в XML-файлах, но в последнее время многие проекты переключаются на сопоставления стилей аннотаций. Вы узнаете об аннотациях в этом руководстве, но если вы хотите ознакомиться с устаревшими сопоставлениями XML, посмотрите, например, на эту ссылку .

Допустим, вы настраиваете режим гибернации с помощью простой Java, без a.cfg.xml файл, тогда у вас был бы такой код, как этот:

(Совет родителям: Не копируйте этот код вслепую).

    // Hibernate specific configuration class
    MetadataSources sources = new MetadataSources( standardRegistry );
    // add class using JPA/Hibernate annotations for mapping
    sources.addAnnotatedClass( User.class );

Что давайте впадем в спячку, зная, что он у вас есть User.class , в котором есть аннотации (самое главное, аннотация @Entity), которые сообщают Hibernate, КАК автоматически сопоставить этот класс с соответствующей таблицей базы данных.

Давайте взглянем на аннотированный класс пользователя.

(Совет родителям: Не копируйте этот код вслепую).

    @Entity
    @Table(name="users")
    public static class User {

        @Id
        private Integer id;

        @Column(name="first_name")
        private String firstName;

        @Column(name="last_name")
        private String lastName;

        //Getters and setters are omitted for brevity
    }

Многое можно было бы сказать об отдельных аннотациях, что выходит за рамки данного руководства. Скорее, мы сосредоточимся здесь на общей картине.

Базовая ГАДОСТЬ с гибернацией

Теперь, когда у вас настроено сопоставление, единственное, что осталось сделать, это получить сеанс (читай: подключение к базе данных) из вашего SessionFactory и сохранить пользователя в базе данных. Правильно, вы не будете писать для этого никакого SQL, Hibernate сделает это за вас:

(Совет родителям: Не копируйте этот код вслепую).

    Session session = sessionFactory.openSession();
    User user = new User();
    user.setFirstName("Hans");
    user.setLastName("Dampf");
    // this line will generate and execute the "insert into users" sql for you!
    session.save( user );

Аналогично, существуют и другие методы, которые позволяют выполнять другие инструкции SQL (например, select, update, delete) без написания какого-либо SQL и без необходимости сопоставления наборов результатов (как в примере JDBC) с вашим классом Java, Hibernate сделает это за вас.

(Совет родителям: Не копируйте этот код вслепую).

    // "select from users where id = 1"
    User user = session.get( User.class, 1 );

    // "update users set...where id=1"
    session.update(user);

    // "delete from useres where id=1"
    session.delete(user);

HQL

Конечно, бывают моменты, когда вам нужно больше контроля и вы хотите написать свои собственные инструкции SQL, особенно для более сложных запросов, чем “выберите, где”.

Hibernate предлагает язык запросов, называемый HQL. HQL похож на SQL, но ориентирован на объекты и фактически независим от диалекта SQL. Таким образом, один и тот же оператор HQL работает для всех баз данных (с тем недостатком, что вы теряете возможности запросов к конкретной базе данных).

Давайте посмотрим, как это выглядит:

(Совет родителям: Не копируйте этот код вслепую).

    List users = session.createQuery("select from User u where u.firstName = 'hans'", User.class).list();

    session.createQuery("update User u set u.lastName = :newName where u.lastName = :oldName")
                .executeUpdate();

Обратите внимание, что в обоих примерах вы получаете доступ к свойствам Java (u.Фамилия) в строке запроса, а не к sqlcolumns. Затем Hibernate преобразует эти инструкции HQL в соответствующие инструкции SQL для конкретной базы данных.

Критерий

В дополнение к HQL, Hibernate предлагает другой язык запросов через API критериев, типобезопасный программный API. Однако настроить его немного сложнее, так как вашему проекту необходим плагин обработки аннотаций для создания “Статической метамодели” ваших аннотированных классов, а сам API также кажется немного громоздким в использовании.

Кроме того, существует две версии API критериев (1 и 2), и многие разработчики считают, что версия 1 на самом деле проще в использовании, чем версия 2, хотя она устарела и, вероятно, будет полностью недоступна в будущем.

В любом случае, давайте взглянем на запрос HQL select выше в форме критериев, который Hibernate преобразует в надлежащий, специфичный для базы данных оператор SQL.

(Совет родителям: Не копируйте этот код вслепую).

    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery criteria = builder.createQuery( User.class );
    Root root = criteria.from( User.class );
    criteria.select( root );
    criteria.where( builder.equal( root.get( User_.firstName ), "hans" ) );
    List users = entityManager.createQuery( criteria ).getResultList();

Как вы можете видеть, вы в основном торгуете удобочитаемостью и простотой для безопасности типов. Шесть строк кода для простого “выберите * из пользователей, где имя =?”

Темная Сторона

Hibernate не просто предлагает простые функции отображения и запроса. Конечно, сопоставления и запросы будут намного сложнее в реальных сценариях, чем те, которые вы нашли выше. Кроме того, он предлагает целый ряд других “удобных” функций, таких как каскадирование, отложенная загрузка, кэширование и многое другое.

Это действительно сложная часть программного обеспечения, которую вы не можете полностью понять, просто скопировав и вставив некоторые онлайн-руководства по коду. Это рано или поздно приведет к тому, что вы заявите, что “Гибернация творит случайную магию, которую никто не понимает” или ее вариант. Потому что вам не хватает базовых знаний о том, что на самом деле делает Hibernate.

Кроме того, работа с Hibernate не означает, что вам больше не нужно заботиться о SQL-операторах. Чем сложнее становится программное обеспечение, тем важнее проверять операторы SQL, которые генерирует Hibernate, или писать собственные оптимизированные операторы SQL/HQL/Criteries.

Что, в свою очередь, означает, что для эффективного использования Hibernate вам необходимо хорошее знание Hibernate и SQL.

Рекомендуемое чтение и просмотр

Хорошим противоядием от этого является чтение Сохраняемости Java с помощью Hibernate книга и работа с ее примерами. В нем 608 страниц, что уже показывает сложность всего этого, но ваши навыки значительно выиграют от его чтения.

Если вам нужна более подробная информация о Hibernate, обязательно посетите сайт Влада Михальчи . Влад действительно является экспертом по вопросам гибернации, он не только ведет блог на Hibernate, но и предлагает книги, видео и т.д.

Вы также можете найти Специальные скринкасты для гибернации на этом сайте, которые обеспечивают плавный и экономящий время быстрый запуск во вселенную гибернации.

JPA

История и обзор

Если вы слышали о Hibernate, скорее всего, вы также слышали о JPA, API сохранения Java. Но что такое JPA? Как это соотносится с библиотекой, такой как Hibernate?

Во-первых, JPA – это просто спецификация, а не реализация или библиотека (в 2006 году была выпущена JPA 1.0 спецификация , а последняя – JPA 2.2 с 2017 года). Таким образом, JPA определяет стандарт, который должна реализовать библиотека баз данных.

И, как вы могли догадаться, Hibernate – не единственная библиотека баз данных Java. Есть и другие очень похожие, такие как EclipseLink, TopLink, о которых вы узнаете больше в следующем разделе.

Теперь самое интересное, что Hibernate, EclipseLink и TopLink все реализуют спецификацию JPA, что означает, что – теоретически – вместо написания определенного кода Hibernate или определенного кода EclipseLink вы пишете конкретный код JPA, добавляете пару файлов конфигурации и требуемую базу данных библиотеки (также называемые: поставщик сохраняемости) в свой проект, и вы можете получить доступ к своей базе данных.

Код

Давайте взглянем на какой-нибудь код. Помните из приведенного выше раздела, что ваша точка входа в спящий режим – это SessionFactory, которая создает сеансы. В JPA эти два элемента называются EntityManagerFactory и EntityManager.

(Совет родителям: Не копируйте этот код вслепую).

    EntityManagerFactory factory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );

    EntityManager entityManager = factory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist( new Event( "Our very first event!", new Date() ) );
    entityManager.persist( new Event( "A follow up event", new Date() ) );
    entityManager.getTransaction().commit();
    entityManager.close();

Если вы внимательно посмотрите на исходный код Hibernate, вы увидите следующее:

    package org.hibernate;

    public interface Session extends SharedSessionContract, EntityManager, HibernateEntityManager, AutoCloseable {
      // methods
    }

    // and

    public interface SessionFactory extends EntityManagerFactory, HibernateEntityManagerFactory, Referenceable, Serializable, java.io.Closeable {
        // methods
    }

Итак, сеанс гибернации ЯВЛЯЕТСЯ EntityManager. SessionFactory ЯВЛЯЕТСЯ EntityManagerFactory. Некоторые методы, такие как режим гибернации “сохранить” или “обновить”, теперь называются “сохраняться” в JPA, но это все.

JPQL, Критерии и т.д.

Наличие Entitymanager – это только половина истории. JPA также поставляется со своим собственным языком запросов JPQL (Java Persistence Query Language), который сильно подвержен влиянию, или, скорее, основан на HQL, языке запросов Hibernate.

То же самое относится и к API Критериев 2.0, который на самом деле является API JPA, а не только для гибернации (как API критериев 1.0).

Таким образом, ваши запросы JPQL или критериев будут работать со всеми реализациями JPA, будь то Hibernate, EclipseLink или TopLink.

Недостатки

Теоретически JPA позволяет вам игнорировать, какую библиотеку поставщика сохраняемости вы используете. Однако это заходит так далеко.

Поскольку спецификация JPA является общим знаменателем для всех библиотек, функции, которые она предлагает, обязательно являются только подмножеством , например, всех функций, которые предлагает Hibernate. В противном случае все библиотеки баз данных были бы точно такими же.

Кроме того, процесс спецификации всегда требует времени, поэтому ему не хватает функций, которые уже могут предложить реализации.

И на практике редко (читай никогда) возникает необходимость в переключении поставщиков сохраняемости после того, как приложение достигнет рабочего состояния. Это просто не вариант использования для переключения в режим гибернации с EclipseLink в производстве, потому что один работает лучше, чем другой.

Наконец, это приведет к тому, что новые проекты примут одну из двух позиций:

  • Старайтесь использовать JPA как можно чаще, добавляя специальные функции Hibernate, в которых в спецификации JPA отсутствуют определенные функции

  • Или используйте обычный режим гибернации до конца.

Оба способа хороши (и вы также можете поменять режим гибернации на EclipseLink и т. Д. здесь)

EclipseLink, TopLink и др.

Если вы дочитали до этого места, вы уже знаете, что существует больше библиотек, таких как Hibernate. В первую очередь на ум приходят два: EclipseLink и (более старый) Ссылка сверху .

Им не хватает доли рынка по сравнению с Hibernate, но вы также найдете проекты, использующие их в корпоративных настройках.

Существуют также другие проекты, такие как Batoo JPA , но в большинстве случаев вы обнаружите, что эти библиотеки заброшены и больше не поддерживаются, потому что для поддержания полностью совместимой с JPA библиотеки требуется немало усилий.

Вам, безусловно, нужно активное сообщество для поддержки дальнейшего развития вашей библиотеки, и у Hibernate, вероятно, самое активное сообщество по состоянию на 2018 год.

Резюме

Реализации JPA – это зрелое и сложное программное обеспечение.

Главное предостережение состоит в том, чтобы думать, что для работы с любой из реализаций JPA не нужно понимать SQL. Они предлагают вам быстрый старт при попытке сопоставить базовые классы с таблицами базы данных. Но в сочетании с отсутствием базовых знаний о том, как работают форумы, это часто приводит к катастрофе позже в вашем проекте, когда все становится трудным.

Основной Вынос

Убедитесь, что у вас есть хорошее представление о том, как, например, работает режим гибернации И как работает SQL и ваша база данных. Тогда вы будете на правильном пути.

Первые библиотеки баз данных

В отличие от подхода, основанного на Java, основное внимание здесь уделяется базе данных.

Не имеет значения, есть ли у вас уже существующая (устаревшая) база данных или вы начинаете новый проект с нуля, где вы бы разработали и написали схему базы данных ПЕРЕД написанием соответствующих классов Java.

ДжуК

jOOQ – популярная библиотека Лукаса Эдера, и она очень хорошо поддерживается. Кроме того, Лукас ведет очень информативный блог обо всем, что связано с базами данных и Java.

По умолчанию вы начинаете с существующей схемы базы данных, а затем запускаете генератор кода jOOQ. Генератор кода создаст набор классов, представляющих таблицы в вашей базе данных, которые позволят вам писать и выполнять типобезопасные SQL-запросы к этим таблицам.

Таким образом, он не такой “высокоуровневый”, как Hibernate, и действительно имеет гораздо меньший набор функций. Но эти функции он выполняет удивительно хорошо.

Представьте, что вы настроили генератор кода Jooq и запустили его в таблице пользователей, которая была представлена в начале этого руководства. jOOQ создаст класс пользовательских таблиц, который, например, позволит вам выполнить следующий запрос к базе данных:

(Совет родителям: Не копируйте этот код вслепую).

    // Imagine an additional SUBSCRIPTIONS table exists
    Result> result =
    create.select(USERS.FIRST_NAME, USERS.LAST_NAME, SUBSCRIPTIONS.ID)
          .from(USERS)
          .join(SUBSCRIPTIONS)
          .on(USERS.SUBSCRIPTION_ID.eq(SUBSCRIPTIONS.ID))
          .where(USERS.FIRST_NAME.eq("Hans"))
          .fetch();

На первый взгляд это похоже на то, что может сделать QueryDSL , и есть определенное перекрытие .

jOOQ, однако, помогает вам не только создавать и выполнять инструкции SQL в соответствии со схемой базы данных, но также помогает вам с CRUD, сопоставлением между записями Java POJO и базы данных, а также поможет вам получить доступ ко всем вашим базам данных (для конкретного поставщика) особенности ( подумайте о функциях окон, сводных данных, запросах ретроспективного анализа, OLAP, хранимых процедурах, функциях, зависящих от поставщика и т. Д.)

(Совет родителям: Не копируйте этот код вслепую).

    // Fetch a user
    UserRecord user : create.fetchOne(USERS, USERS.ID.eq(1));

    // Create a new user, if it doesn't exist yet
    if (user == null) {
        user = create.newRecord(USERS);
        user.setId(1);
        user.setFirstName("Hans");
        user.setLastName("Dampf");
    }

    // Mark the user as a hero and store him
    user.setActionHero(true);

    // Executes an update on existing users, or insert on new ones
    user.store();

Наконец, jOOQ можно, как и в случае с большинством следующих библиотек баз данных, смешивать с библиотекой, подобной Hibernate, везде, где это имеет смысл.

Майбатис

MyBatis – еще одна популярная и активно поддерживаемая база данных – первый выбор. MyBatis сосредоточен вокруг концепции SqlSessionFactory (не путать с Hibernate SessionFactory), которую вы исторически создавали из XML-файла, но в настоящее время вы также можете сделать это с помощью простой Java.

Затем вы можете выполнять инструкции SQL с помощью этого SqlSessionFactory. Эти инструкции SQL либо хранятся в XML-файлах, либо вы аннотируете интерфейсы с ними.

Давайте посмотрим, как выглядит пример аннотации:

(Совет родителям: Не копируйте этот код вслепую).

    package org.mybatis.example;
    public interface UserMapper {
      @Select("SELECT * FROM users WHERE id = #{id}")
      User selectUser(int id);
    }

(Совет родителям: Не копируйте этот код вслепую).

    
    

    
      
    

Затем этот интерфейс позволяет вам писать код, подобный следующему:

(Совет родителям: Не копируйте этот код вслепую).

    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = mapper.selectUser(1);

MyBatis также имеет встроенные функции отображения, т. Е. он может преобразовываться из таблицы в пользовательский объект. Но только в простых случаях, когда, например, имена столбцов совпадают или похожи. В противном случае вам придется указать сопоставления самостоятельно в одном из файлов конфигурации XML.

Кроме того, MyBatis уделяет довольно пристальное внимание своим возможностям динамического SQL , что в основном представляет собой основанный на XML способ создания сложных динамических строк SQL (подумайте, если-еще-когда-либо внутри ваших операторов SQL).

Удобные библиотеки

К настоящему времени вы уже познакомились с довольно большим количеством библиотек баз данных Java, от простого JDBC до гибернации. Есть еще больше, которые квалифицируются как удобные библиотеки поверх любой библиотеки, которую вы выбрали выше. Давайте посмотрим, что это значит.

Весна

Почти десять лет назад разработчики Hibernate пытались утверждать, что никому не нужно использовать Spring, конечно, не в сочетании с Hibernate, и этого простого режима гибернации достаточно. Однако эти дни давно прошли.

Давайте посмотрим, как Spring Framework делает доступ к базе данных более удобным, независимо от того, используете ли вы обычный JDBC, режим гибернации или JPA.

Весенний шаблон JDBC

Одним из старейших вспомогательных классов в Spring Framework является JdbcTemplate. Это в основном удобная оболочка для соединений JDBC (см. Здесь, как работает простой JDBC).

(Совет родителям: Не копируйте этот код вслепую).

    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

    // ...

    jdbcTemplate.execute("CREATE TABLE users(" +
                "id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))");

    // ...

    jdbcTemplate.batchUpdate("INSERT INTO users(first_name, last_name) VALUES (?,?)", names);

    // ...

    jdbcTemplate.query(
                "SELECT id, first_name, last_name FROM users WHERE first_name = ?", new Object[] { "Josh" },
                (rs, rowNum) -> new User(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name"))
        ).forEach(user -> log.info(user.toString()));

Взглянув на код, вы можете увидеть, что, особенно при запросе базы данных и сопоставлении с объектами Java, шаблон JDBC обеспечивает больше удобства, чем прямое использование наборов результатов JDBC. Особенно когда дело доходит до обработки ошибок, закрытия соединения и повторной очистки, что будет сделано за вас.

Весенние Транзакции

Еще одной важной особенностью платформы Spring является то, что она позволяет объявлять транзакции базы данных во всем коде с аннотацией @Transactional .

Все это сводится к тому, что вместо того, чтобы самостоятельно открывать транзакции и закрывать их снова, Spring выполнит обработку транзакций за вас. И обработка транзакций также интегрируется со всеми другими библиотеками баз данных, начиная с собственной библиотеки JDBC Spring и заканчивая каждой реализацией JPA и jOOQ. Таким образом, вы можете использовать обработку транзакций Spring вместе с этими библиотеками.

Давайте посмотрим на пример JPA из предыдущих:

(Совет родителям: Не копируйте этот код вслепую).

    EntityManagerFactory factory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );

    EntityManager entityManager = factory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist( new Event( "Our very first event!", new Date() ) );
    entityManager.persist( new Event( "A follow up event", new Date() ) );
    entityManager.getTransaction().commit();
    entityManager.close();

После “Пружинистости” этот код становится:

(Совет родителям: Не копируйте этот код вслепую).

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void doSomeBusinessLogic() {
        entityManager.persist( new Event( "Our very first event!", new Date() ) );
        entityManager.persist( new Event( "A follow up event", new Date() ) );
    }

Очевидно, что это еще не все, но если вы хотите освежить свои знания о транзакциях базы данных и получить четкое представление обо всех крайних случаях, вы найдете массу практических примеров кода в этой книге здесь.

Весенние данные JPA

Одна из новых библиотек, Spring Data JPA облегчит вам реализацию репозиториев на основе JPA или DAO. Что это значит?

Общим шаблоном при программировании приложений баз данных является наличие класса репозитория/dao для каждого объекта домена. Итак, у вас есть свой класс пользователя и свой класс пользователя. Класс UserRepository позволяет выполнять все обычные операции с базой данных crud (создание-чтение-обновление-удаление) для Пользователя.

А с Spring Data JPA достаточно аннотировать свой пользовательский класс аннотациями JPA и создать пустой класс репозитория, который вы расширяете из одного из классов данных Spring, и вы получаете все основные операции CRUD бесплатно, без необходимости что-либо кодировать:

(Совет родителям: Не копируйте этот код вслепую).

    public interface SimpleUserRepository extends JpaRepository  {

        // JpaRepository contains all of these methods

        List findAll();

        List findAll(Sort sort);

        List findAllById(Iterable ids);

         List saveAll(Iterable entities);

        // and many more...that you can execute without implementing, because Spring Data JPA will
        // automatically generate an implementation for you - at runtime
    }

QueryDSL запрос

Когда вы просматриваете раздел Hibernate/JPA этого руководства, вы можете кое-что заметить: создание сложных или динамических строк HQL/JPQL вручную не является наиболее типобезопасным, читаемым и приятным занятием. И API критериев 2.0 несколько неудобен в использовании, где вам нужно шесть строк кода Java для создания простого SQL select.

Доходы QueryDSL , который в настоящее время может сделать гораздо больше, чем просто прокачка вашей реализации JPA (он также работает, например, для баз данных NoSQL). Однако в этом руководстве мы сосредоточимся на его части, касающейся JPA. Добавив его в свой проект Hibernate/JPA, вы сможете выполнять запросы таким образом (сравните это с Критериями 2.0 запросом выше):

(Совет родителям: Не копируйте этот код вслепую).

    QUser user = QUser.user;
    JPAQuery query = new JPAQuery(entityManager);
    List users = query.select(user)
      .from(user)
      .where(user.firstName.eq("Hans"))
      .fetch();

Откуда берется класс пользователя? QueryDSL автоматически создаст это для вас во время компиляции с помощью плагина компилятора обработки аннотаций. Затем вы можете использовать эти классы для выполнения типобезопасных запросов к базе данных, и они читаются намного лучше, чем эквивалент критериев JPA.

Выбор Правильной ( ™ ) Библиотеки

К настоящему времени вы можете чувствовать себя немного подавленным. Тонна различных библиотек, а затем еще больше удобных опций сверху. Но подводя итог всему, вот несколько примерных рекомендаций (и, как вы, возможно, догадались, не существует “единственного и единственно правильного пути”):

  • Независимо от того, какую библиотеку баз данных вы в конечном итоге выберете, убедитесь, что вы хорошо разбираетесь в SQL и базах данных (чего обычно нет у разработчиков Java).

  • Выберите библиотеку с активным сообществом, хорошей документацией и регулярными выпусками

  • Изучите свои библиотеки баз данных наизнанку, т. Е. Потратьте время на чтение этих 608 страниц JPA

  • Ваш проект будет в порядке с любой реализацией JPA (гибернация – хорошее начало)

  • Это также будет хорошо с jOOQ или любой другой упомянутой базой данных- первые библиотеки

  • Вы также можете объединить эти библиотеки, например, реализацию JPA и jOOQ или обычный JDBC, или добавить больше удобства с помощью таких вещей, как QueryDSL

На сегодня все. Если у вас есть какие-либо вопросы или вы обнаружили какие-либо орфографические ошибки, просто отправьте их в раздел комментариев или напишите мне по электронной почте.

Спасибо за чтение

Признание

Большое спасибо следующим читателям за их подробные отзывы и исправления в этом руководстве: parms , лукаседер , Рагу Эштон .

Оригинал: “https://dev.to/marcobehler/a-guide-to-accessing-databases-in-java-2fdm”