Чтение объектов в Hibernate

Извлечение информации из базы данных в виде коллекции объектов Hibernate может выполнять с использованием :

HQL Hibernate Query Language;
SQL native SQL query;
CriteriaHibernate Criteria API.

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

Чтение данных с использованием HQL

Hibernate может использовать свой мощный язык запросов Hibernate Query Language, который очень похож на родной SQL. В сравнении с SQL, HQL полностью объектно-ориентирован и использует понятия наследования, полиформизма и связывания. Подробное описание языка HQL будет представлено в ближайшие дни.

Следующий метод демонстрирует чтение набора данных пользователей User. HQL запрос формируется с использованием наименования класса. После этого создается запрос Query методом createQuery(sql) объекта сессии и извлекаются данные методом list ().

private void readUsers_HQL()
{
    System.out.println("\n\nЧтение записей : HQL");

    // HQL (Hibernate Query Language) 
    String sql = "From " + User.class.getSimpleName();
    System.out.println("sql = " + sql);

    List<User> users = session.createQuery(sql).list();

    System.out.println("users.size = " + users.size());
    for (Iterator<User> it = users.iterator(); it.hasNext();) {
        User user = (User) it.next();
        System.out.println(user.toString());
    }
}

Запросы Hibernate и данные выводятся в консоль (см. ниже). Обратите внимание, что при создании запроса Query методом createQuery(sql) Hibernate формирует соответствующий запрос чтения списка пользователей. Второй запрос по чтению связанных записей Auto формируется и выполняется уже при распечатке пользователя, т.е. при обращении к связанной сущности (lazy загрузка).


Чтение записей : HQL
sql = From User

Hibernate: select user0_.id as id1_0_, user0_.login as login2_0_,
                  user0_.name as name3_0_ 
              from USERS user0_

users.size = 2

Hibernate: select autos0_.user_id as user_id3_0_0_,
                  autos0_.aid as aid1_1_0_,
                  autos0_.aid as aid1_1_1_,
                  autos0_.name as name2_1_1_,
                  autos0_.user_id as user_id3_1_1_
              from autos autos0_ where autos0_.user_id=?

User {id = 50, login = 'ivan, name = 'Иван', 
      autos =[
              Auto {id = 55, name = 'Volvo, user_id = 50},
              Auto {id = 56, name = 'Skoda, user_id = 50}]}
User {id = 51, login = 'serg, name = 'Сергей', autos =[]}
 

Чтение данных с использованием native SQL-запроса

Hibernate позволяет выполнять native SQL-запросы с использованием org.hibernate.SQLQuery, который создается методом createSQLQuery(String) объекта сессии. Но необходимо учитывать, что в этом случае можно потерять все преимущества HQL (ассоциации, кэширование). Следующий код демонстрирует использование нативного запроса для получения коллекции пользователей.

private void readUsers_SQL()
{
    System.out.println("\n\nЧтение записей : SQL");

    // Использование native SQL query
    String sql = "select ID, LOGIN, NAME from USERS";
    Query query = session.createSQLQuery(sql).addEntity(User.class);

    List<User> users = query.list();
		
    System.out.println("users.size = " + users.size());
    for (Iterator<User> it = users.iterator(); it.hasNext();) {
        User user = (User) it.next();
        System.out.println(user.toString());
    }
}

При формировании объекта Query был добавлен класс User.class методом addEntity, в результате чего метод list объекта Query вернул коллекцию пользователей List<User>. Объект org.hibernate.SQLQuery расширяет возможности двух классов org.hibernate.Query, org.hibernate.SynchronizeableQuery и является потокобезопасным.

Набор прочитанных данных выводится в консоль, представленную ниже. Обратите внимание, что также, как и для HQL, при использовании native SQL второй запрос по чтению связанных сущностей формируется по мере необходимости, т.е. при обращении.


Чтение записей : SQL

Hibernate: select ID, LOGIN, NAME from USERS

users.size = 2

Hibernate: select autos0_.user_id as user_id3_0_0_, \
                  autos0_.aid as aid1_1_0_, \
                  autos0_.aid as aid1_1_1_, \
                  autos0_.name as name2_1_1_, \
                  autos0_.user_id as user_id3_1_1_ \
             from autos autos0_ 
                where autos0_.user_id=?

User {id = 50, login = 'ivan, name = 'Иван', 
      autos =[
              Auto {id = 55, name = 'Volvo, user_id = 50},
              Auto {id = 56, name = 'Skoda, user_id = 50}]}
User {id = 51, login = 'serg, name = 'Сергей', autos =[]}
 
 

Чтение набора объектов, List<Object[]>

При выполнении сложных нативных SQL-запросов для извлечения определенной информации можно сущности к объекту org.hibernate.Query не подключать. В этом случае метод list() объекта Query вернет коллекцию объектов List<Object[]>, как это показано в следующем коде. После этого список объектов можно парсить и использовать по назначению.

private void readObjects()
{
    System.out.println("\n\nЧтение объектов");

    String sql = "select ID, LOGIN, NAME from USERS";
    Query query = session.createSQLQuery(sql);

    List<Object[]> rows = query.list();

    for(Object[] row : rows) {
        User user = new User();
        user.setId     (Integer.valueOf(row[0].toString()));
        user.setLogin                  (row[1].toString());
        user.setName                   (row[2].toString());
        System.out.println(user.toString());
    }
}

В результате выполнения метода readObjects() в консоль будет выведена информация без подгрузки связанных сущностей Auto :


Чтение объектов

Hibernate: select ID, LOGIN, NAME from USERS

User {id = 50, login = 'ivan, name = 'Иван', autos =[]}
User {id = 51, login = 'serg, name = 'Сергей', autos =[]}
 

Использование org.hibernate.Criteria

Интерфейс org.hibernate.Criteria представляет собой объектно-ориентированный запрос на выборку в отношении конкретной сущности и позволяет выполнять запросы без написания SQL кода. Для создания экземпляров Criteria используется класс Session, который выступает в качестве фабрики.

Следующий метод выполняет чтение списка пользователей с именем "Иван". При создании Criteria используется метод createCriteria объекта сессии Session, которому в качестве параметра передается класс объекта. Объект criteria имеет метод add, позволяющий выполнить фильтрацию данных. Для этого методу add необходимо передать параметр ограничения Restrictions с определенными условиями.

private void readUsers_criteria()
{
    System.out.println("\n\nCriteria API");
	Criteria criteria;
    criteria = session.createCriteria(User.class)
                      .add(Restrictions.eq("name", "Иван"));
    List<User> users = criteria.list();

    for (Iterator<User> it = users.iterator(); it.hasNext();) {
        User user = (User) it.next();
        System.out.println(user.toString());
    }
}

Результат выполнения метода readUsers_criteria выведен в консоль :


Criteria API

Hibernate: select this_.id as id1_0_0_, \
                  this_.login as login2_0_0_, \
                  this_.name as name3_0_0_ \
              from USERS this_ \
                  where this_.name=?
Hibernate: select autos0_.user_id as user_id3_0_0_, \
                  autos0_.aid as aid1_1_0_, \
                  autos0_.aid as aid1_1_1_, \
                  autos0_.name as name2_1_1_, \
                  autos0_.user_id as user_id3_1_1_ 
              from autos autos0_ 
                  where autos0_.user_id=?

User {id = 50, login = 'ivan, name = 'Иван', 
      autos =[
              Auto {id = 55, name = 'Volvo, user_id = 50},
              Auto {id = 56, name = 'Skoda, user_id = 50}]}
 

Подробное описание org.hibernate.Criteria с примерами представлено здесь.

Фильтрация данных в Hibernate

Для чтения данных с фильтрацией можно использовать как org.hibernate.Criteria, представленный выше, так и native SQL. Метод readUsers демонстрирует извлечение отдельной записи пользователя, у которой логин соответствует значению параметра метода "filter" :

private void readUsers(final String filter)
{
    String sql;
    // Использование native SQL query с условием
    sql = "select ID, LOGIN, NAME from USERS where login like :log";
    Query query = session.createSQLQuery (sql)          // SQL
                         .addEntity (User.class)        // Class
                         .setParameter ("log", filter); // Condition
    List<User> users = query.list();

    System.out.println("users.size = " + users.size());
    for (Iterator<User> it = users.iterator(); it.hasNext();){
        User user = (User) it.next();
        System.out.println(user.toString());
    }
}

При создании объекта SQLQuery (native SQL) была добавлена сущность (addEntity) и определен параметр "log" (setParameter). В консоли увидим следующую информацию :


Hibernate: select ID, LOGIN, NAME from USERS where login like ?

users.size = 1
User {id = 50, login = 'ivan, name = 'Иван', 
      autos =[
              Auto {id = 55, name = 'Volvo, user_id = 50},
              Auto {id = 56, name = 'Skoda, user_id = 50}]}
 

Чтение отдельной записи

Если известен идентификатор сущности Id, то объект сессии Session позволяет прочитать запись. Для этого можно использовать метод get или load. Отличия методов get и load представлено на странице Hibernate в вопросах и ответах. Следующий код демонстрирует чтение записи пользователя с идентификатором Id=51 :

User user = (User) session.load(User.class, 51);
if (user != null)
    System.out.println("\n\n" + user.toString());

Скачать пример

Исходный код рассмотренного на странице примера использования различных способов Hibernate для чтения данных в виде проекта Eclipse, включающий все необходимые библиотеки hibernate, можно скачать здесь (8.02 Mб).

  Рейтинг@Mail.ru