Блог вебразработчика
  • ГЛАВНАЯ
  • ПОДПИСКА

Hibernate 4: UserType пользовательский тип данных (часть 2)

Окт18
2013
Написал Tatyana

hibernate-logo В этой статье речь пойдет о нюансах реализации вспомогательных (но не менее важных) методов интерфейса UserType: deepCopy, isMutable, disassemble, assemble и replace. О том для чего и как в целом использовать UserType можно прочитать в первой части статьи. В этой статье для примера будут также использоваться классы User, AuditDate и AuditDateUserType из первой части.

Итак, для правильной реализации пользовательского типа первым делом нужно решить является ли Ваш объект mutable (изменяемым). Пример пользовательского типа AuditDateUserType в первой части статьи как раз является реализацией типа для изменяемого объекта. Теперь рассмотрим в чем же разница. Для immutable объектов предназначена, пожалуй, сама простая (и самая распространенная) реализация перечисленных выше методов. Так как поля объекта никогда не будут изменяться и для определения изменения состояния достаточно выполнить проверку равенства по ссылке:

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (null == x || null == y)
        {
            return false;
        }
        return x == y;
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        if (x != null) {
            return x.hashCode();
        }

        return 0;
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) 
                                                  throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) 
                                                  throws HibernateException {
        return original;
    }
  • deepCopy — используется для создания снапшотов состояния объекта после любой персистент операции. Среди перечисленных здесь методов является, пожалуй, самым важным, потому что именно от качества снапшотов объекта и реализации метода equals зависит дальнейшая обработка текущего состояния объекта. Название метода говорит само за себя, он должен возвращать полную копию объекта. Но это справедливо только для mutable объектов. Для immutable же напротив с целью оптимизации метод должен возвращать не копию, а просто принимаемый аргумент. А в случае если equals объектов осуществляется по ссылке, то не возвращать копию объекта просто жизненно важно, иначе вы получите непредвиденные апдейты во время закрытия транзакции и других операций.
  • isMutable — возвращает true, если объект типа может изменяться. Используется для оптимизации при работе с объектами, содержащими поля immutable типа, внутри коллекций.
  • disassemble — конвертирует объект в вид, пригодный для хранения в кэше второго уровня.
    assemble — восстанавливает объект из сериализованного вида при получении объекта из кэша второго уровня.
    В случае с изменяемыми объектами эти два метода должны возвращать полную копию объектов.
  • replace — вызывается когда необходимо выполнить слияние двух объектов. Для immutable достаточно вернуть первый аргумент, для mutable объекта следует вернуть полную копию первого аргумента. Лишь в некоторых случаях для составных объектов есть смысл копировать значения полей по отдельности.

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

    @Test
    public void auditDataSaveTest()
    {
        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
        
        // создадим в БД нового пользователя
        User user = new User();
        user.setName("John");
        user.setAudit(new AuditDate(new LocalDate(), new LocalDate()));
        session.save(user);
        session.refresh(user);
        System.out.println(user.getAudit().getModifiedDate());

        // изменим дату его редактирования на 1 день
        user.getAudit().setModifiedDate(new LocalDate().plusDays(1));
        session.flush();
        session.refresh(user);
        System.out.println(user.getAudit().getModifiedDate());

        session.getTransaction().commit();
        session.close();
    }

Вывод в консоль будет следующим:

Hibernate: insert into user (createdDate, modifiedDate, name) values (?, ?, ?)
Hibernate: select user0_.id as id0_0_, user0_.createdDate as createdD2_0_0_, user0_.m
2013-10-17
Hibernate: update user set createdDate=?, modifiedDate=?, name=? where id=?
Hibernate: select user0_.id as id0_0_, user0_.createdDate as createdD2_0_0_, user0_.m
2013-10-18

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

Теперь изменим реализацию AuditDateUserType так, чтобы он считал объект AuditDate неизменяемым, несмотря на то, что AuditDate на самом деле остается mutable.

AuditDateUserType:

public class AuditDateUserType implements UserType {

    @Override
    public int[] sqlTypes() {
        return new int[] { StandardBasicTypes.TIMESTAMP.sqlType(),
		StandardBasicTypes.TIMESTAMP.sqlType() };
    }

    @Override
    public Class<AuditDate> returnedClass() {
        return AuditDate.class;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names,
	    SessionImplementor session, Object owner)
	    throws HibernateException, SQLException {
        AuditDate auditData = new AuditDate();
        Timestamp created = rs.getTimestamp(names[0]);
        if (created != null) {
            auditData.setCreatedDate(new LocalDate(created));
        }
        Timestamp modified = rs.getTimestamp(names[1]);
        if (created != null) {
            auditData.setModifiedDate(new LocalDate(modified));
        }

        return auditData;
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index,
	    SessionImplementor session) 
	    	    throws HibernateException, SQLException {
        AuditDate auditData = (AuditDate) value;
        if (null != auditData.getCreatedDate()) {
            Timestamp createdTimestamp = new Timestamp(auditData
		    .getCreatedDate().toDateTimeAtStartOfDay().getMillis());
            st.setTimestamp(index, createdTimestamp);
        }
        else {
            st.setNull(index, StandardBasicTypes.TIMESTAMP.sqlType());
        }
        if (null != auditData.getModifiedDate()) {
            Timestamp modifiedTimestamp = new Timestamp(auditData
		    .getModifiedDate().toDateTimeAtStartOfDay().getMillis());
            st.setTimestamp(index + 1, modifiedTimestamp);
        }
        else {
            st.setNull(index + 1, StandardBasicTypes.TIMESTAMP.sqlType());
        }
    }

    // имплементация методов для immutable объектов

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (null == x || null == y)
        {
            return false;
        }
        // больше не делегируем вызов метода equals AuditDate
        return x == y;
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        if (x != null) {
            return x.hashCode();
        }

        return 0;
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) 
                                                throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) 
                                                throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) 
                                                throws HibernateException {
        return original;
    }

Теперь, если мы попробуем выполнить тот же auditDataSaveTest, то получим следующую картину:

Hibernate: insert into user (createdDate, modifiedDate, name) values (?, ?, ?)
Hibernate: select user0_.id as id0_0_, user0_.createdDate as createdD2_0_0_, user0_.m
2013-10-17
Hibernate: select user0_.id as id0_0_, user0_.createdDate as createdD2_0_0_, user0_.m
2013-10-17

Мы видим, что обновление записи не происходит. Почему? Hibernate не видит наших изменений потому что сам объект AuditDate остался тот же, а изменения его полей мы больше не отслеживаем.
При такой реализации мы предполагаем, что поля объекта не могут изменяться, а только ссылка на сам объект. Если в auditDataSaveTest заменить строку

user.getAudit().setModifiedDate(new LocalDate().plusDays(1));

на инициализацию нового объекта AuditDate

user.setAudit(new AuditDate(new LocalDate(), new LocalDate().plusDays(1)));

тогда мы все-таки получим ожидаемое нами обновление.

Все методы описанные в этой статье работают взаимосвязано, в случае возникновения ошибок нельзя исправить работу только одного из них. Например, выполнение методов deepCopy и equals всегда логически связано, нельзя возвращать в deepCopy копию объекта без корректной проверки равенства снапшотов в equals.

  • Нравится
  • Tweet

Опубликовано в Hibernate ORM - Помечено Hibernate
Рассказать всем Twitter Facebook Delicious StumbleUpon E-Mail
← Hibernate 4: UserType пользовательский тип данных (часть 1)
BrowserMob Proxy + Selenium: автоматизация сбора данных о производительности →

Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/u0420283/data/www/internetka.in.ua/wp-includes/class-wp-comment-query.php on line 405

Свежие записи

  • WebDriver и SSL Untrusted certificate
  • Видеозапись выполнения тестов Selenium
  • Selenium WebDriver: basic авторизация
  • BrowserMob Proxy + Selenium: автоматизация сбора данных о производительности
  • Hibernate 4: UserType пользовательский тип данных (часть 2)

Поиск

Рубрики

  • Hibernate ORM
  • SEO
  • Разное
  • Тестирование
    • JUnit
    • Selenium
    • Thucydides

Метки

Actions AJAX Alert AutoIt ChromeDriver Exceptions ExpectedConditions FindElement FirefoxDriver Hibernate InternetExplorerDriver Java Javascript Jenkins JUnit4 Maven PageFactory Page Object RemoteWebDriver Select Selenium IDE Selenium Server Selenium WebDriver switchTo Thucydides WebDriverWait XPath Автоматизированное тестирование база данных заработок в сети сеть Интернет скорость продвижения сайта статейное продвижение услуги продвижения

Реклама


Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.
Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Блог вебразработчика
Функциональное тестирование и продвижение сайтов

Яндекс.Метрика