Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Statement vs Session


Автор: Platon 6.12.2007, 22:59
Здравствуйте, уважаемые.

Не хочу показаться глупым, но мне кажется, что использование Hibernate меня как-то ограничивает. У меня 3 причины думать так:
1. Необходимо пройти специализированные курсы (или самостоятельно не один день посидеть над книжками), чтоб не запороть проект, надеясь, что Hibernate сделает за тебя всё правильно.
2. 10-15 % производительности тоже не лишние. (слабый аргумент, но озвучить стоит)
3. Пропадает свобода (правда частичная) в смысле UserType, специфических запросов так просто уже не получить :( а жаль. (собствено ради этого пункта я и создал тему)

Есть много чего хорошего в hibernate, безусловно... но как быть с 3-м пунктом?

Автор: Platon 6.12.2007, 23:55
Чего темнить, задам пример:
3 таблички:
car_mark
record_id
name
<...>

car_model
record_id
mark_id
name
<...>

cars
record_id
model_id
<...>

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

SELECT mark_id, COUNT( * )
FROM car_mark
LEFT JOIN car_model ON car_mark.record_id = car_model.mark_id
RIGHT JOIN car ON car.model_id = car_model.record_id
GROUP BY mark_id



Автор: check 7.12.2007, 00:22
Platon,  можно ведь использовать http://www.hibernate.org/hib_docs/v3/reference/en/html/querysql.html.

Добавлено через 1 минуту и 40 секунд
Конечно тогда не будет переносимости между разными СУБД.

Автор: COVD 7.12.2007, 00:35
Цитата

Не хочу показаться глупым, но мне кажется, что использование Hibernate 


Это большой философский вопрос, потому что вместо последнего (Hibernate) можно много чего подставить.  smile  Я только не понял, где здесь Statement и Session? Наверное потому, что никогда не пользовался Hibernate (не разобрался пока. Наверное, должно быть страшно, но пока петух не клюнул). Когда обнаруживается рутина в работе, тогда и появляется стимул к освоению инструментов, избавляющих от нее. 

Автор: tux 7.12.2007, 00:38
Такой запрос легко перенести на HQL. Не вижу проблем. Специфичные для СУБД вещи конечно используя Hibernate реализовать не удастся, там ведь никто и не заставляет использовать его всегда. Просто нужно искать какой-то компромис - там где выгоднее использовать HQL, использовать его, а остальных случаях использовать native SQL. Вот и все. Кто кого ограничивает мне не понятно. 

Цитата(Platon @  6.12.2007,  22:59 Найти цитируемый пост)
Необходимо пройти специализированные курсы (или самостоятельно не один день посидеть над книжками), чтоб не запороть проект, надеясь, что Hibernate сделает за тебя всё правильно.

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

Автор: SoulKeeper 7.12.2007, 01:04
Тема довольно интересная smile Давно поглядываю в сторону Hibernate, но никак руки не доходят, хотя то что у них на сайте написано звучит очень даже заманчиво. Хотелось бы услышать отзывы\сравнения о преймущаствах\недостатках технологий.

Автор: w1nd 7.12.2007, 02:00
Цитата(Platon @  6.12.2007,  22:59 Найти цитируемый пост)
10-15 % производительности тоже не лишние.

Откуда такая цифра?


Автор: tux 7.12.2007, 02:06
Цитата(SoulKeeper @  7.12.2007,  01:04 Найти цитируемый пост)
Хотелось бы услышать отзывы\сравнения о преймущаствах\недостатках технологий. 

Сравнения с чем? 

Любая библиотека/технология применима, подходит или не подходит в конкретных условиях, в конкретном проекте или задаче. Я могу сказать "Hibernate - это супер, используйте и радуйтесь", а кто-то другой "Hibernate - отстой, все что делали с его использованием пришлось переделать" потому что Hibernate использовался неоправданно или просто неправильно. И оба будем по-своему правы. Ну и какого сравнения ты ждешь? Получишь набор диаметрально противоположных мнений и все, как их потом фильтровать? Расскажи подробно о задаче, в которой ты собираешься его использовать, может быть что-нибудь посоветуем. Это касается не только Hibernate, а вообще любой технологии.

Добавлено через 3 минуты и 32 секунды
Цитата(w1nd @  7.12.2007,  02:00 Найти цитируемый пост)
Откуда такая цифра?

По-моему хибернейтовцы сами где-то на сайте писали про 10%. Сейчас наверное не найду упоминания. Цифра, конечно, странная. smile

Автор: serger 7.12.2007, 06:51
Цитата(tux @ 7.12.2007,  02:06)
По-моему хибернейтовцы сами где-то на сайте писали про 10%. Сейчас наверное не найду упоминания. Цифра, конечно, странная. smile

Для отчётности ;)

Автор: Platon 7.12.2007, 09:24
Ну, блин, полуночники!!!

check, весьма познавательная стетейка.

Цитата(COVD @  7.12.2007,  01:35 Найти цитируемый пост)
Я только не понял, где здесь Statement и Session?

Литературный прием ;) Statement и Session как олицетворение JDBC и Hibernate соответственно.

На самом деле, мое мнение о hibernate крайне положительное. Всё-таки как не крути, а все объекты из БД проецируются в память наиболее естественным образом. Приятно удивило, что в пределах 1-й сессии вызов get() ссылается на 1 и тот же объект, приятно, что есть возможность создания наиболее естественным образом иерархии классов, связь объектов и много чего другого...

Но что-то консервативное во мне отвергает его.

Добавлено через 9 минут и 35 секунд
по статье native SQL, ч понял, что можно использовать этот финт:
Код

sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
        .setResultTransformer(Transformers.aliasToBean(CatDTO.class))

На сколько я понял, этот CatDTO не является персистентной сущностью?

Автор: Platon 7.12.2007, 10:46
Что-то не получается поработать с рефлексией:
Код

public class Test {
    public static void main(String[] args) {
        HibernateUtil.init();
        Query q = HibernateUtil.getSession().createSQLQuery("SELECT car_mark.record_id, car_mark.name, COUNT( * ) AS amount " +
                "FROM car_mark " +
                "LEFT JOIN car_model ON car_mark.record_id = car_model.parent_id " +
                "RIGHT JOIN car ON car.model_id = car_model.record_id " +
                "GROUP BY car_mark.record_id").setResultTransformer(Transformers.aliasToBean(Mon.class));
        List l = q.list();
        System.out.println(l);
    }
}

public class Mon {
    public long record_id;
    public String name;
    public int amount;

    public Mon() {    }

    public Long getRecord_id() {
        return record_id;
    }

    public void setRecord_id(Long record_id) {
        this.record_id = record_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }
}


Цитата

Exception in thread "main" org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of platon.yanaidu.test.Mon.record_id

Автор: SoulKeeper 7.12.2007, 10:59
Цитата(tux @  7.12.2007,  02:06 Найти цитируемый пост)
Сравнения с чем? 


В теме и в первом посте написано что с чем ;)

Автор: alexadr 7.12.2007, 13:41
также жду решения проблемы с данным запросом!

Автор: w1nd 7.12.2007, 13:46
Мэппинг на бочку smile

Автор: tux 7.12.2007, 14:02
Цитата(SoulKeeper @  7.12.2007,  10:59 Найти цитируемый пост)
В теме и в первом посте написано что с чем ;) 

Цитирую для лучшей усвояемости.

Цитата(Platon @  6.12.2007,  22:59 Найти цитируемый пост)
Не хочу показаться глупым, но мне кажется, что использование Hibernate меня как-то ограничивает. У меня 3 причины думать так:
1. Необходимо пройти специализированные курсы (или самостоятельно не один день посидеть над книжками), чтоб не запороть проект, надеясь, что Hibernate сделает за тебя всё правильно.
2. 10-15 % производительности тоже не лишние. (слабый аргумент, но озвучить стоит)
3. Пропадает свобода (правда частичная) в смысле UserType, специфических запросов так просто уже не получить :( а жаль. (собствено ради этого пункта я и создал тему)

Внимание, вопрос. Hibernate нужно сравнить с UserType, специализированными курсами, книжками, третьим пунктом, 10-ю процентами или "запороть проект"?

Автор: Platon 7.12.2007, 14:55
w1nd, на самом деле маппинга никакого не проводил, думая, что .setResultTransformer(Transformers.aliasToBean(Mon.class)); не нуждается в маппировании.

Добавлено через 1 минуту и 40 секунд
или aliasToBean тоже нуждается в маппировании?

И ещу уж вопрос, что лучше? Маппирование или аннотации? Мне к душе ближе аннотации, глаз не режут, но как я вижу, профы в основном пользуются xml маппингом.

Автор: Platon 7.12.2007, 15:29
Читая книжку по hibernate, наткнулся на интересный термин "проблема n + 1 запросов".
Это к слову о том, что необходимо хорошенько изучить hibernate чтоб с ним нормально работать.
А то ведь многие программисты и не знают, что гробят БД от того, что не видят, какие запросы выполняются. Так, сазать,  нельзя прочувствовать то, что руками не написано.

Добавлено через 31 секунду
Хотя, опять же оговорюсь, такое случается от неопытности ^_^

Автор: AlexeyVorotnikov 7.12.2007, 15:42
Цитата(Platon @  7.12.2007,  14:55 Найти цитируемый пост)
И ещу уж вопрос, что лучше? Маппирование или аннотации? Мне к душе ближе аннотации, глаз не режут, но как я вижу, профы в основном пользуются xml маппингом. 

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

Цитата(Platon @  7.12.2007,  15:29 Найти цитируемый пост)
А то ведь многие программисты и не знают, что гробят БД от того, что не видят, какие запросы выполняются.

Как это они БД гробят?

Автор: serger 7.12.2007, 15:44
Цитата(Platon @ 7.12.2007,  09:24)
Ну, блин, полуночники!!!

Это я уже с утра на работе писал ;)

Автор: AlexeyVorotnikov 7.12.2007, 15:48
Цитата(Platon @  7.12.2007,  15:29 Найти цитируемый пост)
"проблема n + 1 запросов".

Что это за проблема?

Автор: Platon 7.12.2007, 16:40
Цитата(AlexeyVorotnikov @  7.12.2007,  16:48 Найти цитируемый пост)
Что это за проблема? 

Наверно http://www.ayende.com/Blog/archive/7627.aspx подойдет, хотя я не вникал...

Добавлено через 39 секунд
Цитата(AlexeyVorotnikov @  7.12.2007,  16:42 Найти цитируемый пост)
Как это они БД гробят?

Ну, в смысле производительность БД резко падает.

Автор: SoulKeeper 7.12.2007, 19:28
Цитата(tux @  7.12.2007,  14:02 Найти цитируемый пост)
Внимание, вопрос. Hibernate нужно сравнить с UserType, специализированными курсами, книжками, третьим пунктом, 10-ю процентами или "запороть проект"?



Ну если нефиг делать, то естесвенно что нужно запороть десяток проектов. Вопрос в Hibernate vs JDBC через обычные Statement. Если хочется пофлудить, то будь так добр и флуди в другом месте.  smile 

Автор: tux 7.12.2007, 23:07
Цитата(SoulKeeper @  7.12.2007,  19:28 Найти цитируемый пост)
Если хочется пофлудить, то будь так добр и флуди в другом месте.

Молодой человек, научитесь культуре общения и в первую очередь вопросы задавать. 

Автор: Platon 9.12.2007, 22:25
Народ! Я так и не получил ответа на вопрос по запросу :(
Как правильно оформить такой запрос?

Автор: tux 9.12.2007, 22:35
Цитата(Platon @  9.12.2007,  22:25 Найти цитируемый пост)
Как правильно оформить такой запрос? 

Да практически так же. Только здесь многое будет зависеть от маппинга. Например, так:
Цитата

SELECT markId, COUNT( * ) c FROM carMark join carModels GROUP BY mark_id

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

Автор: Platon 9.12.2007, 22:40
tux, Хотите сказать тот пример
Код

.setResultTransformer(Transformers.aliasToBean(Mon.class));

не катит, и для чего тогда это??? Обязательно маппить? Я конечно понимаю, что логично маппить каждую таблицу, но создавать по классу на запрос, дело утомительное.

Автор: tux 9.12.2007, 22:59
Если тебе нужен SQL-запрос, то нужно будет создать java-класс, в который будут выгружаться результаты. Неужели настолько много запросов, чтобы создать под каждый бин результата?

Автор: Platon 9.12.2007, 23:03
tux, Про бины нет вопросов. Но дополнительный маппинг.
Вот, я нашел какой-то метод, видимо им мало кто пользовался Transformers.aliasToBean(Mon.class)
Но я не понял почему первый же сеттер бина не проходит, выдает ошибку.

Автор: LSD 11.12.2007, 00:28
Попробуй для начала назвать property согласно спецификациям Java, т.е. recordId.

Автор: AlexeyVorotnikov 11.12.2007, 10:27
У тебя тип самого record_id -- long, а тип аргумента в сеттере -- Long. Поэтому и IllegalArgumentException вылетает. (Скорее всего)
Приведи всё к одному типу и посмотри, что получится.

Автор: LSD 11.12.2007, 12:18
Цитата(AlexeyVorotnikov @  11.12.2007,  10:27 Найти цитируемый пост)
У тебя тип самого record_id -- long, а тип аргумента в сеттере -- Long. Поэтому и IllegalArgumentException вылетает. (Скорее всего)

Это смотря как они определяют тип property, если по get/set методам, то это все равно, там просто будет autoboxing на автомате и все.

Автор: Platon 11.12.2007, 20:19
Подведем предварительный итог:
Я понял, как работают Query! и это меня очень радует, понял, что Hibernate как никогда освобождает меня от бремени использования рукописных запросов.

Теперь по делу:
Все-таки не могу добиться результата работы данного запроса :(
Код

public class Test {
    public static void main(String[] args) {
        HibernateUtil.addClass(CarMark.class);
        HibernateUtil.addClass(CarModel.class);
        HibernateUtil.addClass(Car.class);
        HibernateUtil.init();
        Query q = HibernateUtil.getSession().createQuery("SELECT mark.recordId, COUNT( * ) AS amount FROM Car car JOIN car.model model JOIN model.mark mark GROUP BY mark.recordId").setResultTransformer(Transformers.aliasToBean(Mon.class));
        List l = q.list();
    }
}


Код

package platon.yanaidu.test;

import javax.persistence.*;

@Entity
public class Car {
    @Id
    @GeneratedValue
    @Column(name = "record_id")
    public Long recordId;
    @ManyToOne
    @JoinColumn(name = "model_id")
    public CarModel model;
}



Код

package platon.yanaidu.test;

import javax.persistence.*;

@Entity
@Table(name = "car_mark")
public class CarMark {
    @Id
    @GeneratedValue
    @Column(name = "record_id")
    public Long recordId;

    public String name;
}



Код

package platon.yanaidu.test;

import javax.persistence.*;
@Entity
@Table(name = "car_model")
public class CarModel {
    @Id @GeneratedValue @Column(name = "record_id")
    public Long recordId;

    @ManyToOne()
    @JoinColumn(name = "parent_id")
    public CarMark mark;
}



Код

package platon.yanaidu.test;

public class Mon {
    public Long record_id;
    public String name;
    public int amount;

    public Mon() {    }

    public Long getRecord_id() {
        return record_id;
    }

    public void setRecord_id(Long record_id) {
        this.record_id = record_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }
}

Генерируется следующий родной запрос:
Код

    select
        carmark2_.record_id as col_0_0_,
        count(*) as col_1_0_ 
    from
        Car car0_ 
    inner join
        car_model carmodel1_ 
            on car0_.model_id=carmodel1_.record_id 
    inner join
        car_mark carmark2_ 
            on carmodel1_.parent_id=carmark2_.record_id 
    group by
        carmark2_.record_id


Вот это я сварганил, но выдается ошибочка:
Цитата

Exception in thread "main" org.hibernate.PropertyNotFoundException: Could not find setter for 0 on class platon.yanaidu.test.Mon
    at org.hibernate.property.ChainedPropertyAccessor.getSetter(ChainedPropertyAccessor.java:44)


Автор: AlexeyVorotnikov 11.12.2007, 22:08
Код

SELECT mark.recordId AS record_id, COUNT( * ) AS amount FROM Car car JOIN car.model model JOIN model.mark mark GROUP BY mark.recordId

Автор: Platon 12.12.2007, 06:36
Долгожданный ответ!!! Спасибо.

Только подправь recored_id на record_id на случай, если кто-то будет интересоваться темой.
И мне чтоб окончательно заработало надо было поменять setter в Mon
Код

public void setAmount(int amount) {
        this.amount = amount;
    }



на 

Код

public void setAmount(Long amount) {
        this.amount = amount.intValue();
    }

Автор: Platon 12.12.2007, 07:35
Если уж быть педантично точным, то требуемый запрос был:
Код

SELECT mark.recordId AS record_id, mark.name as name, COUNT( car.recordId ) AS amount FROM Car car JOIN car.model model RIGHT JOIN model.mark mark GROUP BY mark.recordId


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)