Основы Hibernate



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

    Долго думал, о чем же написать свой «первый» топик… Слово первый не зря взял в кавычки, так как первый топик на самом деле уже был, опыт был к сожалению неудачный — дело закончилось баном.  Решил больше не копипастить. Уверенности тому, что надо написать что-то свое, придал вот этот топик. Решил твердо — пусть это будет и редко, но буду писать сам.

    Ну, едем дальше!

    Совсем недавно, по роду свой деятельности, мне пришлось столкнуться с таким понятием как ORM — (англ. Object-relational mapping). В двух словах ORM — это отображение объектов какого-либо объектно-ориентированного языка в структуры реляционных баз данных. Именно объектов, таких, какие они есть, со всеми полями, значениями, отношениями м/у друг другом.

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

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

    Немного подумав, решил написать так называемый «Виртуальный автопарк». Суть парка такова: есть автобусы, есть маршруты и есть водители. Автобусы и маршруты связаны отношением один ко многим, т.е. на одном маршруте может кататься сразу несколько автобусов. Водители и автобусы связаны отношением многие ко многим, т.е. один водитель может водить разные автобусы и один автобус могут водить разные водители. Вроде ничего сложного.
    Вот схема базы данных.

    За качество не ругайте — под рукой не оказалось нормального инструмента таблички рисовать…
    Вот ссылка на дамп, снятый с базы, вдруг кто-то решит все это дело поднять :)
    Приступаем к коду. Во первых нам необходимо описать классы наших сущностей, т.е. класс автобуса, водителя и маршрута.
    Класс автобус.
    package logic;

    import java.util.Set;
    import java.util.HashSet;

    public class Bus {
      private Long id;
      private String number;
      private Set drivers = new HashSet();
      private Long route_id;

      public Bus() {
      }
      public void setId(Long id) {
        this.id = id;
      }
      public void setNumber(String number) {
        this.number = number;
      }
      public void setDrivers(Set drivers) {
        this.drivers = drivers;
      }
      public void setRoute_id(Long route_id) {
        this.route_id = route_id;
      }
      public Long getId() {
        return id;
      }
      public String getNumber() {
        return number;
      }
      public Set getDrivers() {
        return drivers;
      }
      public Long getRoute_id() {
        return route_id;
      }
    }
    * This source code was highlighted with Source Code Highlighter.

    Класс водитель.
    package logic;

    import java.util.Set;
    import java.util.HashSet;

    public class Driver {
      private Long id;
      private String name;
      private String surname;
      private int age;
      private Set busses = new HashSet();

      public Driver() {
      }
      public void setBusses(Set busses) {
        this.busses = busses;
      }
       public Set getBusses() {
        return busses;
      }
      public void setId(Long id) {
        this.id = id;
      }
      public void setName(String name) {
        this.name = name;
      }
      public void setSurname(String surname) {
        this.surname = surname;
      }
      public void setAge(int age) {
        this.age = age;
      }
      public Long getId() {
        return id;
      }
      public String getName() {
        return name;
      }
      public String getSurname() {
        return surname;
      }
      public int getAge() {
        return age;
      }
    }
    * This source code was highlighted with Source Code Highlighter.

    И класс маршрут.
    package logic;

    import java.util.Set;
    import java.util.HashSet;

    public class Route {
      private Long id;
      private String name;
      private int number;
      private Set busses = new HashSet();

      public Route(){
      }
      public void setId(Long id) {
        this.id = id;
      }
      public void setName(String name) {
        this.name = name;
      }
      public void setNumber(int number) {
        this.number = number;
      }
      public void setBusses(Set busses) {
        this.busses = busses;
      }
      public Long getId() {
        return id;
      }
      public String getName() {
        return name;
      }
      public int getNumber() {
        return number;
      }
      public Set getBusses() {
        return busses;
      }
    }
    * This source code was highlighted with Source Code Highlighter.

    Заметьте, что все классы сущностей должны соответствовать Java naming conventions, т.е. у них должны быть обязательно геттеры, сеттеры и конструктор по умолчанию. Ничего сложного :)

    Теперь для наших классов необходимо описать маппинг в виде xml-файлов, эти файлы как раз и будут отвечать за взаимодействие наших объектов с Hibernate и с базой данных.
    Bus.hbm.xml
    <hibernate-mapping>
      <class name=«logic.Bus» table=«busses»>
        <id column=«bus_id» name=«id» type=«java.lang.Long»>
          <generator class=«increment»/>
        </id>
        <property column=«number» name=«number» type=«java.lang.String»/>
        
        <set name=«drivers» table=«busDriver» lazy=«false»>
          <key column=«bus_id»/>
          <many-to-many column=«driver_id» class=«logic.Driver»/>
        </set>

      </class>
    </hibernate-mapping>
    * This source code was highlighted with Source Code Highlighter.


    Driver.hbm.xml
    <hibernate-mapping>
      <class name=«logic.Driver» table=«drivers»>
        <id column=«driver_id» name=«id» type=«java.lang.Long»>
          <generator class=«increment»/>
        </id>
        <property column=«name» name=«name» type=«java.lang.String»/>
        <property column=«surname» name=«surname» type=«java.lang.String»/>
        <property column=«age» name=«age» type=«java.lang.Integer»/>

        <set name=«busses» table=«busDriver» lazy=«false»>
          <key column=«driver_id»/>
          <many-to-many column=«bus_id» class=«logic.Bus»/>
        </set>

      </class>
    </hibernate-mapping>
    * This source code was highlighted with Source Code Highlighter.

    Route.hbm.xml
    <hibernate-mapping>
      <class name=«logic.Route» table=«routes»>
        <id column=«route_id» name=«id» type=«java.lang.Long»>
          <generator class=«increment»/>
        </id>
        <property column=«name» name=«name» type=«java.lang.String»/>
        <property column=«number» name=«number» type=«java.lang.Integer»/>

        <set name=«busses» lazy=«false»>
          <key column=«route_id»/>
          <one-to-many class=«logic.Bus»/>
        </set>

      </class>
    </hibernate-mapping>
    * This source code was highlighted with Source Code Highlighter.

    Теперь давайте немного разберемся в этих xml-ных макаронах :)
    • Тег hibernate-mapping я думаю понятен, тут ничего говорить не стоит.
    • Тег class имеет два параметра: параметр name — Имя класса (необходимо указывать полный путь с учетом структуры пакетов) и параметр table — имя таблицы в базе данных, на которую будет маппиться наш класс.
    • Тег id описывает идентификатор. Параметр column указывает на какую колонку в таблице будет ссылаться поле id нашего объекта, так же указываем класс и указываем generator, который отвечает за генерацию id.
    • Тег property описывает простое поле нашего объекта, в качестве параметров указываем имя поля, его класс и имя колонки в таблице.
    • Тег set описывает поле в котором содержится некий набор(коллекция) объектов. Тег содержит параметр name — имя поля нашего объекта, параметр table — имя таблицы связи(в случае отношения многие ко многим) и параметр lazy. Lazy, если меня не подводит моя память, с английского — ленивый. Так называемые ленивые коллекци, сейчас постараюсь объяснить понятнее. Когда мы в параметре lazy указываем значечение false, то у нас при получении объекта Route из базы вместе с объектом достается и коллекция объектов Bus, так как busses это поле объекта Route. А если в качестве параметра мы указываем значение true, то коллекция объектов Bus не вытаскивается, для ее получения надо явно вызывать метод route.getBusses(). Вот предположим такой очень хороший пример. Есть объект город, в него входит массив районов, в каждый район — массив улиц, в каждую улицу — массив домов и так далее до людей, живущих в квартирах. Предположим мы хотим вытянуть из базы названия районов. Если укажем lazy = false, то помимо районом у нас вытянется еще огромный объем «ненужных» данных, если же lazy = true, то мы получим то что надо и ничего лигнего.
    • Тег key имеет параметр column, который говорит, на какую колонку в таблице связи будет ссылаться поле нашего объекта.
    • Тег many-to-many описывает связь типа многие ко многим, в качестве параметров тег использует column — имя колонки второй колонки в таблице связи и параметр class, указывающий какого класса будут объеты на той стороне.


    Теперь создадим главный конфигурационный файл hibernate.cfg.xml, файл, откуда он будет дергать всю необходимую ему информацию.
    <hibernate-configuration>

      <session-factory>
        <property name=«connection.url»>jdbc:mysql://localhost/autopark</property>
        <property name=«connection.driver_class»>com.mysql.jdbc.Driver</property>
        <property name=«connection.username»>root</property>
        <property name=«connection.password»/>
        <property name=«connection.pool_size»>1</property>
        <property name=«current_session_context_class»>thread</property>
        <property name=«show_sql»>true</property>
        <property name=«dialect»>org.hibernate.dialect.MySQL5Dialect</property>

        <mapping resource=«logic/Bus.hbm.xml»/>
        <mapping resource=«logic/Driver.hbm.xml»/>
        <mapping resource=«logic/Route.hbm.xml»/>

      </session-factory>
      
    </hibernate-configuration>
    * This source code was highlighted with Source Code Highlighter.

    Тут я не буду особо вдаваться в объяснение, думаю многим и так все понятно :) Скажу, что надо только в конце не забыть добавить тег mapping и указать в качестве параметра resources файлы конфигурации ваших бинов.

    Теперь создадим класс, который будет хавать наш конфиг-файл и возвращать нам объект типа SessionFactory, который отвечает за создание hibernate-сессии.
    package util;

    import org.hibernate.cfg.Configuration;
    import org.hibernate.SessionFactory;

    public class HibernateUtil {
      private static final SessionFactory sessionFactory;
        static {
          try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
          } catch (Throwable ex) {
            System.err.println(«Initial SessionFactory creation failed.» + ex);
            throw new ExceptionInInitializerError(ex);
          }
        }

        public static SessionFactory getSessionFactory() {
          return sessionFactory;
        }
    }
    * This source code was highlighted with Source Code Highlighter.


    Теперь нам осталось разобраться со взаимодействием нашего приложения с базой данных. Для этого для каждого класса-сущности, определим интерфейс, содержащий набор необходимых методов (Я приведу только один интерфейс и одну его реализацию, интерфейсы и реализации для др. классов подобны этим.)
    package DAO;

    import logic.Bus;
    import logic.Driver;
    import logic.Route;

    import java.util.Collection;
    import java.sql.SQLException;

    public interface BusDAO {
      public void addBus(Bus bus) throws SQLException;
      public void updateBus(Long bus_id, Bus bus) throws SQLException;
      public Bus getBusById(Long bus_id) throws SQLException;
      public Collection getAllBusses() throws SQLException;
      public void deleteBus(Bus bus) throws SQLException;
      public Collection getBussesByDriver(Driver driver) throws SQLException;
      public Collection getBussesByRoute(Route route) throws SQLException;

    }
    * This source code was highlighted with Source Code Highlighter.


    Теперь определим реализацию этого интерфейса в классе BusDAOImpl
    package DAO.Impl;

    import DAO.BusDAO;
    import logic.Bus;
    import logic.Driver;
    import logic.Route;
    import java.sql.SQLException;
    import java.util.Collection;
    import java.util.ArrayList;
    import java.util.List;
    import util.HibernateUtil;
    import javax.swing.*;
    import org.hibernate.Session;
    import org.hibernate.Query;

    public class BusDAOImpl implements BusDAO {

      public void addBus(Bus bus) throws SQLException {
        Session session = null;
        try {
          session = HibernateUtil.getSessionFactory().openSession();
          session.beginTransaction();
          session.save(bus);
          session.getTransaction().commit();
        } catch (Exception e) {
          JOptionPane.showMessageDialog(null, e.getMessage(), «Ошибка при вставке», JOptionPane.OK_OPTION);
        } finally {
          if (session != null && session.isOpen()) {

            session.close();
          }
        }
      }

      public void updateBus(Long bus_id, Bus bus) throws SQLException {
        Session session = null;
        try {
          session = HibernateUtil.getSessionFactory().openSession();
          session.beginTransaction();
          session.update(bus);
          session.getTransaction().commit();
        } catch (Exception e) {
          JOptionPane.showMessageDialog(null, e.getMessage(), «Ошибка при вставке», JOptionPane.OK_OPTION);
        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
      }

      public Bus getBusById(Long bus_id) throws SQLException {
        Session session = null;
        Bus bus = null;
        try {
          session = HibernateUtil.getSessionFactory().openSession();
          bus = (Bus) session.load(Bus.class, bus_id);
        } catch (Exception e) {
          JOptionPane.showMessageDialog(null, e.getMessage(), «Ошибка 'findById'», JOptionPane.OK_OPTION);
        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
        return bus;
      }

      public Collection getAllBusses() throws SQLException {
        Session session = null;
        List busses = new ArrayList<Bus>();
        try {
          session = HibernateUtil.getSessionFactory().openSession();
          busses = session.createCriteria(Bus.class).list();
        } catch (Exception e) {
          JOptionPane.showMessageDialog(null, e.getMessage(), «Ошибка 'getAll'», JOptionPane.OK_OPTION);
        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
        return busses;
      }

      public void deleteBus(Bus bus) throws SQLException {
        Session session = null;
        try {
          session = HibernateUtil.getSessionFactory().openSession();
          session.beginTransaction();
          session.delete(bus);
          session.getTransaction().commit();
        } catch (Exception e) {
          JOptionPane.showMessageDialog(null, e.getMessage(), «Ошибка при удалении», JOptionPane.OK_OPTION);
        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
      }

      public Collection getBussesByDriver(Driver driver) throws SQLException {
        Session session = null;
        List busses = new ArrayList<Bus>();
        try {
          session = HibernateUtil.getSessionFactory().getCurrentSession();
          session.beginTransaction();
          Long driver_id = driver.getId();
          Query query = session.createQuery(
              " select b "
                  + " from Bus b INNER JOIN b.drivers driver"
                  + " where driver.id = :driverId "
          )
              .setLong(«driverId», driver_id);
          busses = (List<Bus>) query.list();
          session.getTransaction().commit();

        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
        return busses;
      }

      public Collection getBussesByRoute(Route route){
        Session session = null;
        List busses = new ArrayList<Bus>();
        try {
          session = HibernateUtil.getSessionFactory().getCurrentSession();
          session.beginTransaction();
          Long route_id = route.getId();
          Query query = session.createQuery(«from Bus where route_id = :routeId „).setLong(“routeId», route_id);
          busses = (List<Bus>) query.list();
          session.getTransaction().commit();

        } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
        }
        return busses;
      }

    }
    * This source code was highlighted with Source Code Highlighter.


    Еще рас скажу, что реализации DriverDAOImpl и RouteDAOImpl будут аналогичны этой.
    Наибольший интерес для нас представляют два последних метода, взгляните на них повнимательнее. Как происходит общение с базой? От объекта SessionFactory создается новая или получается текущая сессия, зачем начинается транзакция, выполняются необходимые действия, коммит транзакции и закрытие сессии. Вроде ничего сложного :) Обратите внимание, на то, каким синтаксисом описан запрос к базе. Это так называемый HQL (Hibernate Query Language) HQL представляет собой объектно-ориентированный язык запросов, возможности его широки, но мной настолько широко еще не осилены :) Помимо save, load, update, delete и HQL, можно пользоваться и обычным SQL. Например:
    String query = "SELECT driver_id, name, surname, age FROM drivers";
    List drivers = new ArrayList();
    drivers = (List) session.createSQLQuery(query).list();



    Теперь создадим класс фабрики, к которой будем обращаться за нашими реализациями DAO, от которых и будем вызывать необходимые нам методы.
    public class Factory {
      
      private static BusDAO busDAO = null;
      private static DriverDAO driverDAO = null;
      private static RouteDAO routeDAO = null;
      private static Factory instance = null;

      public static synchronized Factory getInstance(){
        if (instance == null){
          instance = new Factory();
        }
        return instance;
      }

      public BusDAO getBusDAO(){
        if (busDAO == null){
          busDAO = new BusDAOImpl();
        }
        return busDAO;
      }

      public DriverDAO getDriverDAO(){
        if (driverDAO == null){
          driverDAO = new DriverDAOImpl();
        }
        return driverDAO;
      }

       public RouteDAO getRouteDAO(){
        if (routeDAO == null){
          routeDAO = new RouteDAOImpl();
        }
        return routeDAO;
      }
    }
    * This source code was highlighted with Source Code Highlighter.


    Теперь нам осталось создать какой-либо демонстрационный класс, для того, чтобы посмотреть и опробовать все то, что мы написали. Ну, не будем тянуть, вот этот класс, возможно не самый удачный, но все же :)
    public class Main {
      public static void main(String[] args) throws SQLException {
        
        Collection routes = Factory.getInstance().getRouteDAO().getAllRoutes();
        Iterator iterator = routes.iterator();
        System.out.println("========Все маршруты=========");
        while (iterator.hasNext()) {
          Route route = (Route) iterator.next();
          System.out.println("Маршрут : " + route.getName() + "  Номер маршрута : " + route.getNumber());
          Collection busses = Factory.getInstance().getBusDAO().getBussesByRoute(route);
          Iterator iterator2 = busses.iterator();
          while (iterator2.hasNext()) {
            Bus bus = (Bus) iterator2.next();
            System.out.println("Автобус № " + bus.getNumber());

          }
        }

        Collection busses = Factory.getInstance().getBusDAO().getAllBusses();
        iterator = busses.iterator();
        System.out.println("========Все автобусы=========");
        while (iterator.hasNext()) {
          Bus bus = (Bus) iterator.next();
          Collection drivers = Factory.getInstance().getDriverDAO().getDriversByBus(bus);
          Iterator iterator2 = drivers.iterator();
          System.out.println("Автобус № " + bus.getNumber());
          while (iterator2.hasNext()) {
            Driver driver = (Driver) iterator2.next();
            System.out.println("Имя : " + driver.getName() + "   Фамилия: " + driver.getSurname());

          }
        }

      }
    }
    * This source code was highlighted with Source Code Highlighter.

    Еще раз скажу, что может не самый удачный вариант использования всего нами написанного, но для этого уже лучше GUI писать или Web-интерфейс, а это уже другая песня :)

    P.S.. Скажу, что на 100%-ую правильность я не претендую, это мое личное имхо, однако очень надеюсь, что это станет для кого-то полезным материалом.

    P.S.S. Все библиотеки и файлы качать тут.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 112
    • +2
      Для подсветки синтаксиса можно пользоваться, например, Source Code Highlighter. Опционально для написания текста статей можно использовать ХабраРедактор.
      • 0
        То что надо, огромное спасибо.
      • +7
        Всё бы хорошо, но зачем xml, когда есть анотации? Ведь гораздо удобнее написать например
        @Id
        @Column(name= "id")
        private Long id;


        xml лишь размазывает модель по разным файлам.
        • 0
          Согласен. Посчитал, что в основах лучше описать с помощью xml, дабы у людей, не знакомых с этим, не возникло путаницы.
          • 0
            Мне кажется, что с аннотациями было бы проще и понятнее.
            • –10
              А вы спросите у c++'ников или php'истов - знают ли они, что такое аннотации в java.
              • +1
                Знаете, если C++'ник полезет править java код, он наверное спросит по то, что не знает у гугла :)
            • 0
              IMHO в XML менее читабельно.
            • 0
              зачем же по разным, весь маппинг можно засунуть в один файл.
              • 0
                А как быть с проектами, где persistant-классов не единицы и даже не десятки, а сотни?
                • 0
                  конечно, на аннотациях описывать все много проще и читабельнее, но веть не об этом речь, а о том что можно. как и в других подходах здесь тоже есть свои минусы...
              • +1
                Но добавляет гибкости.
                Я использую nHibernate - порт под .net, при интеграции с Castle Active Record можно использовать аттрибуты в коде, но тогда мапинг размазывается.

                Я лично делаю класс entity, например Users.cs и к нему Users.hbm.xml.

                1. Легко найти мапинг класса
                2. Код не замусорен всей этой мапинг хренью, т.к., по идее интерфейс обращения с БД должен быть абстрагирован и извлечен в отдельный от бизнес логики слой infrastructure
                • –3
                  Аннотации зашивают логику конфигурирования в бинарный код. Любое изменение конфигурации влечёт полную пересборку проекта. Это антипаттерн.
                  • +1
                    Не согласен с тем, что это - антипаттерн. Не могу представить себе ситуацию, когда нужно поменять мэппинг, но не менять класс. Даже если надо добавить поле - его надо добавить и в класс. Максимум что приходит в голову - null, not null и может быть длина строки. Но такие вещи обычно надо закладывать на этапе проектирования базы.
                    • 0
                      Привязка к схеме базы данных — ещё большая глупость.
                      Нужно работать с бизнеслогикой и, отталкиваясь от неё, подбирать подходящую схему БД. А так как бизнес-логика периодически изменяется, то схема БД тоже не стоит на месте.

                      Не нужно "политику" (к коей относится конфигурация) зашивать в логику.
                      • 0
                        А кто зашивает политику в логику?
                        Вы определитесь, если вы правите бизнес-логику, то вам доступны исходники. А значит никто не мешает поправить аннотации в классах-сущностях. Если же вы просто меняете схему БД, то да, достаточно поменять xml-ки не пересобирая проект, но зачем менять схему БД просто так, без сущностей?
                      • 0
                        увы, такие вещи очень часто на практике требуется поменять существенно позже этапа проектирования базы, особенно «null-not null», когда клиента вдруг осеняет, что он не совсем правильно сформулировал свои потребности)

                        Или другой вариант: решили вы внедрить слой хранимых процедур, дабы поисследовать, как там с производительностью будет. Когда весь маппинг отделён, такие изменения касаются только его. А если всё вперемешку — перелопачивать код.

                        Пример из другой сферы:
                        Вот когда-то очень давно я считал, что отдельный CSS-файл — это страшно неудобно. Ну как, так у меня вся информация о теге прямо в нём же, в атрибуте style, а тут надо куда-то в другое место лезть, там нужные классы искать... Однако, я думаю, ясно, что разделение html и css - это хорошо и полезно, поелику это есть разные аспекты описания, им и быть в разных местах, и меняться независимо.

                        Вот и пара «код-маппинг» (структура класса => маппинг на хранилище) аналогична в принципе паре «html-css» (структура документа => маппинг на экран). И без особых на то причин, лучше их не смешивать.
                    • 0
                      Как общий пример ORM в Java так имхо описать - лучше. Поскольку некоторые ORM(TopLink например) не особо используют аннотации.
                      • 0
                        Есть стандарт доступа к данным - JPA и он использует аннотации.
                        • 0
                          Безусловно. Но аннотации в различных проектах и различных системах используются в разном количестве. В моем текущем проекте с использованием Oracle TopLink аннотаций практически нет. А сталкиваться тем кто только начинает знакомится с этими технологиями придется с разными проектами явно. Не лучше сначала описать маппинг через xml?
                        • 0
                          А вот Toplink Essentials в Glassfish их очень даже использует.
                        • 0
                          Аннотации полностью позволяют сделать то, что можно в xml? Задавать имена индексов и прочие мелочи?
                          Когда я общался с хибернатом такого вроде бы нельзя было в аннотациях.
                          • 0
                            Не знаю ничего такого, что можно сделать на xml но не сделать на аннотациях, хотя не исключаю что такое может быть.
                            P.S. @IndexColum("index_name") ;)
                            • 0
                              Всё понял, большое спасибо.
                              • 0
                                Круто. Переименование/добавление индекса в БД -> пересборка кода бизнес-логики? ))
                                • 0
                                  Каждый день переименовываете индексы?
                                  • 0
                                    Мне кажется, или мы говорили о разделении хранения и бизнес-логики?
                          • 0
                            Перенесите, пожалуйста, в http://habrahabr.ru/blog/java/.
                            Теперь Вы можете писать не только в персональный блог.
                            • +1
                              Все как бы на JPA уже переползли. Ну а вообще запихнуть тысячу страниц Java Persistence with Hibernate в один пост - слишком самонадеянно.
                              • +1
                                java-блог наполняется и это радует :)
                                однако мне больше нравится использовать хибернейт в обёртке GORM(Grails): ни тебе xml-конфигов, ни мильоов геттеров-сеттеров, ни фабрик с истансами - красота :)
                                • 0
                                  Есть в GORM и свои проблемы, но в 99% случаев да, гораздо удобнее.
                                  • 0
                                    некоторые люди говорят, что GORM - самая сильная черта grails :)
                                  • 0
                                    И тормоза в бонус ?(:
                                    Чем за удобство придётся платить?
                                    • 0
                                      хм, почему же сразу тормоза?
                                      геттеры-сеттеры создаются при генерации байткода, тут тормозов нет
                                      аннотации/xml-конфиги генерятся при сборке проекта, я думаю.
                                      вот в динамических методах типа Race.findAllByCityLikeAndStateLike ещё возможен оверхед, да и то я не уверен.
                                      • 0
                                        А какая есть информация, чтобы из неё сделать xml или аннотации?

                                        Я просто хочу узнать чем пожервовали ради удобства, не бывает так, чтобы ничем :(
                                        • 0
                                          Да ничем особо не жертвовали. Кроме статической типизации. ;)
                                          • 0
                                            тут возможны два варианта:
                                            1) информации никакой не нужно - таблицы в БД генерятся по domain классам
                                            2) легаси БД уж есть, тогда мы просто объявляем маппинг вида
                                            static mapping = {
                                            table 'people'
                                            version false
                                            columns {
                                            id column:'person_id'
                                            }
                                            }
                                            • 0
                                              Ситауция: есть джава классы, как сгенерировать по ним схему в БД без доп информации (маппингов или аннотаций).
                                              Я, например, не понимаю, как по джава-коду можно сгенерировать мелочи типа индексов, их имён и прочего (миграции удобней писать).
                                              С легаси базой — всё понятно.
                                              • 0
                                                1) выкидываем геттеры-сеттеры для удобства и читабельности
                                                2) пишем grails create domain-class Foo
                                                3) в получившийся файл Foo.groovy переносим содержимое, полученное на этапе 1)
                                                4) добавляем ограничения(constrains)
                                                5) добавляем связи, "нестандартные" типы, "нестандартные" индексы и "нестандартные" маппинги по вкусу в пару строк того же groovy-кода в тот же groovy-класс.
                                                далее либо пишем grails generate-all, а потом grails run-app и оцениваем получившийся полный CRUD, либо просто grails shell и получаем табличку(таблички) в БД

                                                зы может мне в противовес hibernate осветить GORM, есть желающие?
                                                • 0
                                                  Не знаю как всем, но мне было бы интересно про GORM узнать.

                                                  Груви немного используем, но больше как тестовое — потому как он медленней. Плюс многое (управление сессиями, транзакциями, фабриками) за нас делает за нас Spring, посему хибернат сложностью особо не напрягает.

                                                  Но способ GORM, который вы описали выглядит проще (:
                                                  • 0
                                                    grails, вообще говоря, Spring(да и hibernate) тоже использует.

                                                    кстати, насколько сильно заметна неторопливость groovy в вебприложениях?
                                                    • 0
                                                      Да, я знаю, что используется Spring, это хорошо (:

                                                      Мы груви не используем везде, есть опыт как языка скриптования и для отладок. Во многих местах мы отказались уже от Ognl, тоже из-за скорости. Порядок скоростей OGNL и Groovy думаю сходен.
                                                      • 0
                                                        c OGNL дела, увы, не имел, но groovy всё же побыстрее должен быть, думаю. Groovy вообще хорош практически идеальной интеграцией с java - в большинстве случаев .java можно превратить в .groovy с минимальными изменениями, ну а "узкие" места groovy-кода переписать на java. В groovy 1.6 скорости разработчики ещё прибавили.
                                                      • 0
                                                        Я активно использую Groovy. Поскольку в задаче узкое место - это БД, то разницы с Java практически нет.
                                                    • +1
                                                      зы может мне в противовес hibernate осветить GORM, есть желающие?

                                                      Желающие наверняка есть
                                                      Лично я с удовольствием почитаю.
                                                      Заранее благодарен
                                              • 0
                                                Судя по всему оверхэд будет лишь в первый раз. Потом query кэшируется.
                                          • –1
                                            Обычно рекомендуется из примеров убирать геттеры/сеттеры, заменяя им чем-нибудь вроде
                                            // ...
                                            или
                                            // Default getters and setters
                                            • +3
                                              Возник такой вопрос: а почему в классе Bus вы написали
                                              private Long route_id;

                                              а не
                                              private Long roprivate Route route;ute_id;

                                              ? Если так писать, то теряется половина смысла использования Hibernate :(

                                              Если немного переписать модель (только модель, основной ваш код я пока не трогаю) на базе ваших примеров, но с небольшой переделкой путем
                                              1) использования аннотаций (наиболее актуальный вариант на данный момент),
                                              2) изоляции логики связанной с хранением объектов от самих объектов,
                                              3) использования Generics,
                                              то можно получить примерно следующее:


                                              Собственно наши классы:
                                              @Entity
                                              @Table(name = "busses")
                                              public class Bus extends ManagedEntity {
                                                @NotNull
                                                @Length(max = 6)
                                                private String number;  
                                                
                                                @NotNull
                                                @ManyToOne
                                                @JoinColumn(name = "fk_route")
                                                private Route route;
                                                
                                                @OneToMany(mappedBy = "driver")
                                                private Set<Driver> drivers;

                                                // ... 
                                              }


                                              @Entity
                                              @Table(name = "drivers")
                                              public class Driver extends ManagedEntity {
                                                @NotNull
                                                @Length(max = 20)
                                                private String name;
                                                
                                                @NotNull
                                                @Length(max = 20)
                                                private String surname;
                                                
                                                private int age;
                                                
                                                @OneToMany(mappedBy = "bus")
                                                private Set<Bus> busses;
                                                
                                                // ... 
                                              }


                                              @Entity
                                              @Table(name = "routes")
                                              public class Route {
                                                @NotNull
                                                @Length(max = 30)
                                                private String name;
                                                
                                                @NotNull
                                                private int number;
                                                
                                                @OneToMany(mappedBy = "bus")
                                                private Set<Bus> busses;
                                                
                                                // ...
                                              }



                                              ManagedEntity это класс-предок для наших persistant-объектов:
                                              @MappedSuperclass
                                              public class ManagedEntity extends VersionedEntity {
                                                public static final long NULL_LONG = 0L;

                                                @Id
                                                @GeneratedValue
                                                @Column(name = "id")
                                                @NotNull
                                                private long id = NULL_LONG;
                                                
                                                // ...
                                              }



                                              А VersionedEntity - будет обеспечивать оптимистическую блокировку:
                                              @MappedSuperclass
                                              public abstract class VersionedEntity implements Serializable {
                                                @Version
                                                @NotNull
                                                @Column(name = "obj_version")
                                                private long objVersion;

                                                // ...
                                              }



                                              Note: аннотацию @Column я почти всюду опустил, чтобы не засорять пример. По дефолту, если этого аттрибута нет, Hibernate будет использовать то же имя, что и имя поля объекта. А так как у нас имя столбца в таблице всюду совпадает с именем поля у объекта, то можно было @Column вообще не использовать.


                                              Мне кажется, что такой код намного нагляднее, чем вариант с заданием маппинга в XML. Хотя некоторые минусы у этого варианта тоже есть.
                                              • 0
                                                Там в самом начале вместо этой абракадабры
                                                private Long roprivate Route route;ute_id;

                                                должно было быть
                                                private Route route;
                                                • 0
                                                  Спасибо за такой четкий комментарий. Сам сейчас перехожу на использование аннотаций, вынес для себя кое что полезное.
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                    • 0
                                                      Спасибо за комментарий, возьму на заметку.
                                                      • 0
                                                        И где же здесь изоляция хранения? Видна только лапша из бизнес-классов, ограничений на значения полей, названий столбцов в БД и внешних ключей.
                                                        • 0
                                                          Здесь под "изоляцией хранения" понимался тот факт, что из самих бизнесс классов была убрана и вынесена в отдельный класс такая вещь, как id.
                                                      • +1
                                                        Объём написанного кода для такой простой задачи уж очень большой и отпугивает от Hibernate. С использованием анотаций уже лучше, но все равно много. А можно этот пример реализовать во всю "мощь" Hibernate, чтобы оценить все его преимущества?
                                                        P.S. Например, если этот пример переписать на Ruby с ActiveRecord, то кода будет до неприличия мало.
                                                        • 0
                                                          К этому можно добавить HibernateSearch добавляя на нужные домены аннотации и получая классный поиск с автоматическим обновлением индекса при CRUD. А также возможность поднять всё это в кластере. В Eclipse можно установить плагин и делать HQL запросы напрямую в БД. Распределённые транзакции через JTA, кеширование доменов (в том числе в кластере). И туча тонких настроек и фич, которые не доступны в Django или RoR, и с помощью которых можно затюнить ORM под свои нужды.
                                                          • 0
                                                            И самое инетерсное - кэширование.
                                                            Также в Hibernate удобно создавать свои типы данных, назначая им правила мэппинга, приятной фичей являются так называемые компоненты и много других вкусностей.
                                                            • 0
                                                              Ах, да, забыл еще такой удобный инструмент, как hibtools
                                                            • 0
                                                              А зачем? Все тонкие настройки в чистый сиквел. ORM для чего? Для замены сиквела или для удобства работы над частями, где он сложен? Когда ORM сложнее сиквела он мешает.
                                                              • 0
                                                                Тонкие настройки именно по ORM маппингу и выборке доменов, а не по SQL.
                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                                  • 0
                                                                    А вот когда количество табличек перевалит за пару десятков, вот тогда голый SQL будет кошмаром.

                                                                    А если вдруг понадобиться переименовать поле в табличке или поменять его тип, то с голым SQL это будет очень интересное занятие.
                                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                                      • 0
                                                                        Простая?.. В паре десятков мест поменять это разве просто… С hibernate я имею статическую проверку типов при переименовании. Возмем еще, например, вариант, когда надо поле перенести из одной таблички в другую.

                                                                        Лично я боюсь голого SQL по банальной причине — лень. Лень изобретать велосипед. Есть очень большое желание писать

                                                                        #{order.client.fullName}, а не #{listItem[1]} :)

                                                                        Особенно, если нужно выводить не список order'ов, а детали order'а.

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

                                                                • 0
                                                                  вот было не плохо сделать сделать небольшой обзор всех этих фич
                                                                  • 0
                                                                    Надо бы сделать, но времени пока нет. Еще имеет смысл рассмотреть такие системы как Tapestry5 и Wicket. И в целом описать текущее положение дел в java, а то все кричат что в java много классных фреймворков и библиотек (а это правда), но к сожалению никто не делает хороших review по ним... Как у меня появится время обязательно займусь всем этим.
                                                                    • +1
                                                                      почитаю с удовольствием
                                                                • 0
                                                                  если вам нужна мощь hibernate вкупе с простой настройкой и простым использованием, советую взглянуть на GORM:
                                                                  _http://grails.org/GORM
                                                                  • 0
                                                                    спасибо, посмотрю для общего развития
                                                                  • 0
                                                                    На самом деле код примеров мог быть намного компактнее. Например реализация метода getBussesByDriver (см. выше) могла состоять всего из одной строчки:
                                                                    return driver.getBuses();
                                                                    • 0
                                                                      Действительно так, зато хоть немного HQL-я заюзали. Держите плюс! :)
                                                                  • +3
                                                                    Тема статьи хорошая, гораздо лучше чем про стартапы и как заработать миллион.
                                                                    Но ИМХО, лучше все-таки писать о том в чем разбираешься, а не начинаешь разбираться.
                                                                    • 0
                                                                      Не согласен. Если взять большую тему - хибернейт то в ней человек может еще разбираться, в то же время в основах (банально - как написать мэппинг) он уже разобрался. Почему бы ему об этом не написать?
                                                                      • –1
                                                                        Потому что он банально не справится.
                                                                        Без глубокого владения темой не получится выделить важные моменты и подать их структурированно.
                                                                      • 0
                                                                        Есть несколько типов статей: тонкости (которые должен описывать опытный) и начало, побуждающая — вторые вполне могут писать начинающие, им проще — они только что это пережили.
                                                                        • 0
                                                                          Да ладно вам ребята, все с чего-то начинают, будто у нас тут на хабре статьи только старые бородатые программисты пишут - ничего подобного :)
                                                                        • НЛО прилетело и опубликовало эту надпись здесь
                                                                          • 0
                                                                            Если не ошибаюсь, Doctrine вроде как а-ля ActiveRecord (из RoR). Как он по скорости/потреблению ресурсов ?
                                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                                          • 0
                                                                            А меня вот про запросы мучает непонимание. Когда
                                                                            " select b "
                                                                            + " from Bus b INNER JOIN b.drivers driver"
                                                                            + " where driver.id = :driverId "
                                                                            там все понятно, подставляем параметр и всем хорошо... А как писать запрос если нужно выбирать значения в списке? То есть
                                                                            SELECT b from .... WHERE id IN ( 1, 5, 12 ) ... но с учетом того, что 1,5,12 приходит в массиве. Вариант с формированием из массива строки и подставлением ее в запрос я умею, а как сделать по-правильному?
                                                                            • 0
                                                                              В нативном sql только так как ты написал, в hibernate можно так
                                                                              List bookIds = ....
                                                                              Query query = session.createQuery ("from books where books_id in (:booksId)");
                                                                              query.setParameterList("bookId", bookIds);
                                                                              • 0
                                                                                спасибо
                                                                                • 0
                                                                                  Оговорка, под нативным sql я имел ввиду при использование JDBC, короче не так выразился.
                                                                              • 0
                                                                                А еще в Hibernate есть классная вещь - Criteria API, мне кажется в большинстве случаев удобнее и логичнее чем HQL
                                                                              • +2
                                                                                Статья хорошая, все просто и понятно, спасибо.
                                                                                Пара мелких замечаний:
                                                                                - busses -> buses
                                                                                - private Long route_id; -> private Long routeId; согласно Java нотации. Или я не прав?
                                                                                - DAO классы не должны ничего знать о Swing
                                                                                • 0
                                                                                  - имена пакетов всегда пишутся маленькими буквами.
                                                                                  - геттеры getBusDAO и подобные с capital case в названиях полей выглядят убого и не соответствуют Java naming conventions.
                                                                                • +2
                                                                                  Очень радует появление джавы.
                                                                                  Спасибо.
                                                                                  • 0
                                                                                    Геттеры/сеттеры и конструктор по умолчанию это не из Java Naming Conventions, а из соглашений Java Beans
                                                                                    • 0
                                                                                      Немного не в тему, но JOptionPane.showMessageDialog с первым параметром "null" это плохо, лучше сразу отучать себя от такого
                                                                                      • 0
                                                                                        я бы еще посоветовал вынести работу с сессией и транзакциями в отдельное место
                                                                                        Например в интерсептор или обернуть вызовы методов в замыкания
                                                                                        • +1
                                                                                          Как вариант — вынести это, например, в Spring :)
                                                                                          • 0
                                                                                            это самый лучший вариант )
                                                                                            но, думаю, для одной статьи этого многовато )
                                                                                        • 0
                                                                                          Огромное человеческое спасибо за статью!
                                                                                          • 0
                                                                                            Как полагается, ложка дегтя.

                                                                                            Как это ни странно, Hibernate плохо приспособлен для функционирования в среде веб, особенно если вы не пользуетесь EJB контейнером. Проблема в том, что связанные поля и коллекции с lazy fetching не могут использоваться за пределами сессии. Например если в примере автора поле Bus.drivers замепить как lazy, то

                                                                                            BusDAO.getBusById( ... ).getDrivers().get( ... )

                                                                                            не выдаст водителя автобуса, поскольку обращение к полю drivers (и фетчинг коллекции) лежит за пределами сессии. Это происходит всегда, когда вы используете, например, любой mvc фреймворк. В этом случае фетчинг lazy полей может происходить не только в action, но и в момент рендеринга страницы.

                                                                                            Как возможное решение можно написать фильтр для Tomcat, который до обработки запроса открывает новую hibernate-сессию и записывает ее как атрибут в объект request, а после обработки делает commit и закрывает ее.
                                                                                            • 0
                                                                                              Собственно отдельная сессия под каждый запрос (как у автора) - это, конечно, не корректно. Обычно на один запрос к серверу - одна сессия Hibernate (да и транзакция в большинстве случаев - одна).
                                                                                            • 0
                                                                                              Статья хорошая, наверное больше для начинающих.

                                                                                              Я вот когда начинал разбираться с HBM, точнее с его воплощением под .NET взял и сделал помимо мапинга классов(для удобного Create\Save\Update\Delete ОДНОГО эклемента) и всю логику на нем (импорт\экспорт данных\запросы\сортировки и тд) - это была моя главная ошибка - т.к HBM дико медленно работает, нет когда вы достаете один элемент и его , допустим, даллее редактируете это еще нормально, но вот когда вы пытаетесь сделать выборку хотя бы по 10000 тыс элементов(каждый из которых представляет собой достаточно большое дерево - порядка 60 таблиц), или экспортировать из XML(5мб) файла данные в HBM классы, а потом в базу
                                                                                              • –2
                                                                                                >Заметьте, что все классы сущностей должны соответствовать Java naming conventions, т.е. у них должны быть обязательно геттеры, сеттеры и конструктор по умолчанию. Ничего сложного :)

                                                                                                :-OOOOO

                                                                                                То есть ничего сложного в тысячах ненужных строк кода в том случае, когда объекты содержат не пару, а сотню полей???

                                                                                                Господа, извините не удержался - это бред! Это ненужная работа! Написана куча кода для какой цели? Сохранить структуру в Java-класс? Вы хотя бы для себя решили вопрос - зачем Вам нужно написать bus.number вместо recordset("number")?

                                                                                                Вы проделали огромную работу, создали сложную конфигурацию, которую придется поддерживать, привязали свой код максимально к данным (при добавлении поля его придется менять) и? Зачем??

                                                                                                Вам просто нравится работать? Где выгода-то?

                                                                                                Вот смотрите:

                                                                                                RecordSet rs = SELECT("SELECT * FROM BUS");

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

                                                                                                Вот вывел номер автобуса:

                                                                                                System.print(rs("number"));

                                                                                                Все что мне нужно - коннект к SQL RDBMS. И все! И код максимально свободен от изменения данных.

                                                                                                Не занимайтесь ерундой, короче. Будьте проще.
                                                                                                • +1
                                                                                                  Все эти "тысячи строк ненужного кода" генерируются срезствами IDE за пару секунд :)
                                                                                                  А работать напрямую с базой хорошо, когда у вас
                                                                                                  1) очень простая бизнес-логика,
                                                                                                  2) нет сложной валидации данных,
                                                                                                  3) низкие требования к производительности.
                                                                                                  • 0
                                                                                                    Из-за этого они не перестают быть тысячами строк ненужного кода.

                                                                                                    А кто сказал, что мой метод - это работа "напрямую" с БД? Кто мне мешает закешировать эти датасеты на клиенте?

                                                                                                    Насчет производительности говорить бессмысленно. Отдельные решения от hibernate могут замедлится, отдельные - ускориться.
                                                                                                    • 0
                                                                                                      4)маленькая команда (SQL запросы люди могут писать по разному)
                                                                                                      5)одна и таже база (в смысле тип MS SQL или oracle, c HBM очень легко менять тип базы)
                                                                                                      • 0
                                                                                                        Ну во-первых, SQL запросы в hibernate чудовищны просты - это SELECT по уникальному идентификатору и UPDATE по нему же.

                                                                                                        Вот пусть один программист БД и пишет SQL, а остальные его используют.

                                                                                                        Насчет базы - мей би.

                                                                                                        Понимаете я не представляю себе проекта (серьезного), в котором можно взять и заменить базу. Мы в свое время пытались переползти с MS SQL на ORACLE, но поняли быстро, что это нереально. Слишком много работы, слишком много специфических особенностей использовано и т.д....
                                                                                                      • 0
                                                                                                        Низкие требования к производительности - это как раз для hibernate. Он хорош для быстрого старта, для создания прототипа или для небольшого проекта. Мне больше нравится ibatis - сохраняет свободу дейсвтий. Время проведенное за тюнингом и доводкой hibernate практически нивелирует разницу между написанием сиквел-запросов. А так мне нравится в hibernate кэш и работа с сессией. Но то что он сам генерит запросы - это минус.
                                                                                                        • 0
                                                                                                          Это не минус. Это плюс. Это всё ради того, чтобы обеспечить высокую совместимость. И опять же, Хибернейт предоставляет возможность использовать нативные SQL-запросы, если это нужно. Другое дело, что реальная необходимость возникает действительно редко. А собственно HQL - это обобщенный SQL, который Хибернейт сможет подогнать к любой БД.

                                                                                                          У меня был опыт миграции с MySQL на Oracle без Хибернейта и с Хибернейтом. В первом случае мне пришлось вносить изменения чуть ли не в половину более-менее серьезных запросов. Во втором случае оказалось достаточно прикрутить нужный драйвер и подправить конфиг.

                                                                                                          Что касается производительности. Если речь идет о проекте на миллионы пользователей, то тут конечно Хибернейт будет скорее мешать, чем помогать. В такие приложениях нужно всегда писать запросы максимально заточннные под конкретную задачу и конкретную БД. Если же речь идет о бизнес-приложении небольшого и среднего масштаба, то только за счет кэширования производительность вырастает в несколько раз.
                                                                                                      • 0
                                                                                                        1. Любая предметная область состоит из сущностей и отношений между ними, а не из каши атрибутов. Поэтому оперировать объектами удобнее и правильней, нежели полями.
                                                                                                        2. В ORM вы определяете структуру данных и отношения ОДИН РАЗ, и не задумываетесь при выборке данных. В SQL же вы в каждом запросе цепляете абсолютно глупый компот из JOIN и заново указываете связи (несмотря на то, что структура уже определена DDL).
                                                                                                        3. Hibernate-реализация не зависит от движка БД. Чтобы перейти на новый движок вам не нужно будет перелопачивать тонны кода, достаточно поменять пару строчек в конфигурации. Более того, к Hibernate можно прикрутить сторонние движки, например Lucene.
                                                                                                        4. Hibernate позволяет в простой форме реализовать наследование.
                                                                                                        5. Кеш данных, кеш второго уровня и прочие вкусности.
                                                                                                        6. При переименовании таблиц/полей не придется апдейтить все запросы (количество которых может быть вырасти до тысяч), а достаточно лишь поменять меппинг.

                                                                                                        А теперь самое главное:
                                                                                                        bus.getDrivers() намного проще, чем
                                                                                                        SELECT * FROM drivers, busdriver WHERE drivers.driver_id = busdriver.driver_id AND bus_id = xxx

                                                                                                        В добавок, в IDEs типа Eclipse при вводе "bus." вылезет полный список полей объекта. В SQL же запросах постоянно придется консультировать правильное написание полей в структуре данных.
                                                                                                        • 0
                                                                                                          То есть ничего принципиального нового не появляе тся, а сложность и объём возрастает? Всё это можно было сделать в три раза меньше используя только базовое знаение SQL. И это было понятно каждому. А в этой мути без понимания чудо-hibernate не разберёшься. Плюс несколько дополнительных шагов в сосздании работаебщего проекта (все эти танцы с XML) не факт, что положительно скажутся на простоте отладки и поддержки.
                                                                                                          "1. Любая предметная область состоит из сущностей и отношений между ними, а не из каши атрибутов. Поэтому оперировать объектами удобнее и правильней, нежели полями."
                                                                                                          Именно так. Но для этого вы и пишене на Java, а не GW-BASIC. Все те же сущности реализуются и при меньшем числе телодвижений.
                                                                                                          "2. В ORM вы определяете структуру данных и отношения ОДИН РАЗ, и не задумываетесь при выборке данных. В SQL же вы в каждом запросе цепляете абсолютно глупый компот из JOIN и заново указываете связи (несмотря на то, что структура уже определена DDL)."
                                                                                                          Как-то плохо согласуется с ООП. для работы с такого рода данными вам нужно три-вида запросов - инкапсулируйте их в объект. Опять же, объём кода меньше, сложность меньше, телодвижений меньше, понятность больше.
                                                                                                          "3. Hibernate-реализация не зависит от движка БД. Чтобы перейти на новый движок вам не нужно будет перелопачивать тонны кода, достаточно поменять пару строчек в конфигурации. Более того, к Hibernate можно прикрутить сторонние движки, например Lucene."
                                                                                                          Тем, кто пишет программы (тем более реализиующие столь просте отношения) зависящие от движка БД никакой hibernate не поможет. Как я уже говорил - тут несколько запросов - все замечательно укладывается в страницу кода и бедет полная независимость от БД. Используя hibernate вы лишь пытается уйти от ручного написания это кода (котрый пишется один раз), за счёт странных танцев с XML, но сложность от этого только возрастает - используется две дополнительных технологии (XML и hibernate) плюс крайне сомнительная наглядность результата (который кстати с трудом ложится в идеологию ООП).
                                                                                                          "4. Hibernate позволяет в простой форме реализовать наследование". Т.е. все эти мутные class-factory это "простая форма"? Наследование можно реализовать намного проще. тем более в Java.
                                                                                                          "5. Кеш данных, кеш второго уровня и прочие вкусности."
                                                                                                          Тут совсем не понял. Как можно ускорить выборку из БД не нарушая целостность - не понятно. Хотя допускаю.
                                                                                                          "При переименовании таблиц/полей не придется апдейтить все запросы (количество которых может быть вырасти до тысяч), а достаточно лишь поменять меппинг."
                                                                                                          Шутите? Вы, что все SQL запросы в своих программах руками пишите и сто раз поторяете если придётся?! При правильной структуре программы при переименованеии полей нужно лишь изменить одну-две строчки кода и собственно саму базу.
                                                                                                          "А теперь самое главное:
                                                                                                          bus.getDrivers() намного проще, чем
                                                                                                          SELECT * FROM drivers, busdriver WHERE drivers.driver_id = busdriver.driver_id AND bus_id "
                                                                                                          Т.е. после всех вот тех промежуточных классах проще? :) Т.е. инкапсуляция SQL в отдельный класс и реализация всей вон той мути прямо в классе bus это сложнее? :))))
                                                                                                          "В добавок, в IDEs типа Eclipse при вводе "bus." вылезет полный список полей объекта. В SQL же запросах постоянно придется консультировать правильное написание полей в структуре данных."
                                                                                                          Нет, правда, скажите, что Вы не серьёзно!!! Или хотите, я вам продам за сто тыщ мульёнов идею, как не писать в каждом методе SQL код? :)))))
                                                                                                          • 0
                                                                                                            > То есть ничего принципиального нового не появляе тся, а сложность и объём возрастает? Всё это можно было сделать в три раза меньше используя только базовое знаение SQL.

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

                                                                                                            2. ООП здесь не при чем. Зачем делать каждый раз то, что машина должна уметь делать сама (я имею ввиду написание запросов). Структура данных ей известна, необходимые данные - тоже. В чем проблема?
                                                                                                            3. Это был только пример. В Hibernate 3 можно обойтись без XML при помощи аннотаций (см. коментарии выше). Как говорится, тяжело в учении - легко в бою. Один раз попотев над структурой и меппингом, манипуляция с данными становится очень простой и наглядной.
                                                                                                            4. Здесь мы говорим не о самом наследовании, а о его персистенции в базе данных. Наследование-то вы сделали, а кто сохранять его будет?

                                                                                                            > Нет, правда, скажите, что Вы не серьёзно!!! Или хотите, я вам продам за сто тыщ мульёнов идею, как не писать в каждом методе SQL код? :)))))
                                                                                                            Посмотрите коммент от пользователя Regis.
                                                                                                            http://habrahabr.ru/blog/java/47258.html#comment1011773
                                                                                                            Если Вы мне предложите что-нибудь проще и короче, то я возьму все свои слова обратно.
                                                                                                        • 0
                                                                                                          Простите, а Вы что, динозавр?
                                                                                                        • 0
                                                                                                          Вот холивар развели )))

                                                                                                          HB тормозит - это даже я могу точно, использование кэша спасает, но не особо, иногда когда точно уверен в чем-то, то можно отключить транзакции при сохранении (ускоряет примерно в 10 раз процесс)

                                                                                                          Ошибки в Hibernate сложнее отследить.

                                                                                                          НО HBM это лишь путь эволюции ООП под БД, не знаю уместно ли сравнение, но все-таки на asmе можно написать идеальную программу, которая будет оптимизирована идеально и даст вам полную свободу действий, но все почему-то пишут приложения под Java, С# и с++
                                                                                                          • 0
                                                                                                            А вот скажите пожалуйста, какая область применения Hibernate? Я имею ввиду в проектах какого масштаба? Сайты писать на это штуке 100 процентов изврат=) Очевидно что для штук потяжелее. Только я почему-то всегда думал что в крупных проектах с огромными базами и ограничениями не более 0,01 секунды на простой запрос твикают непосредственно SQL и используют по максимуму процедурные фишки скажем Oracle.
                                                                                                            • 0
                                                                                                              Область применения такая что, в крупных проектах со схемой в полсотни таблиц, хибернэйт как раз и позволяет объеденить схему бд с объектной моделью приложения. А это, имхо, большое дело.
                                                                                                              В тоже время никто не мешает юзать хранимые процедуры под конкретную субд вкупе с хибернэйтом.
                                                                                                              • 0
                                                                                                                Вы немного не поняли мой вопрос. Я как бы не спрашивал зачем нужен ORM («позволяет объединить схему бд с объектной моделью приложения»), а зачем именно такой сложный в использовании ORM. Просто отразить таблички в объекты и обратно можно без всего этого ужаса и тон кода, примеры — Grails/Gorm, Rails/ActiveRecord.
                                                                                                            • 0
                                                                                                              Ссылочки поправьте, пожалуйста=) (на дамп и на библиотеки с файлами) За статью спасибо!

                                                                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.