Как использовать одну сессию hibernate configuration java
Перейти к содержимому

Как использовать одну сессию hibernate configuration java

  • автор:

Hibernate. Основные принципы работы с сессиями и транзакциями

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

Библиотека Hibernate является самой популярной ORM-билиотекой и реализацией Java Persistence API. Часто используется как ORM-провайдер в обычных Java-приложениях, контейнерах сервлетов, в частности, в сервере приложений JBoss (и его потомке WildFly).

1). Объекты-сущности (Entity Objects)

Рассмотрим две сущности — пользователя и его задачи:

Теперь приведём классы-сущности для этих таблиц:

Об аннотациях JPA можно прочитать здесь.

2). Интерфейс Session

Интерфейс org.hibernate.Session является мостом между приложением и Hibernate. С помощью сессий выполняются все CRUD-операции с объектами-сущностями. Объект типа Session получают из экземпляра типа org.hibernate.SessionFactory, который должен присутствовать в приложении в виде singleton.

3). Состояния объектов

Объект-сущность может находиться в одном из 3-х состояний (статусов):

  • transient object. Объекты в данном статусе — это заполненные экземпляры классов-сущностей. Могут быть сохранены в БД. Не присоединены к сессии. Поле Id не должно быть заполнено, иначе объект имеет статус detached ;
  • persistent object. Объект в данном статусе — так называемая хранимая сущность, которая присоединена к конкретной сессии. Только в этом статусе объект взаимодействует с базой данных. При работе с объектом данного типа в рамках транзакции все изменения объекта записываются в базу;
  • detached object. Объект в данном статусе — это объект, отсоединённый от сессии, может существовать или не существовать в БД.
  • persist(Object) — преобразует объект из transient в persistent, то есть присоединяет к сессии и сохраняет в БД. Однако, если мы присвоим значение полю Id объекта, то получим PersistentObjectException — Hibernate посчитает, что объект detached, т. е. существует в БД. При сохранении метод persist() сразу выполняет insert, не делая select.
  • merge(Object) — преобразует объект из transient или detached в persistent. Если из transient, то работает аналогично persist() (генерирует для объекта новый Id, даже если он задан), если из detached — загружает объект из БД, присоединяет к сессии, а при сохранении выполняет запрос update
  • replicate(Object, ReplicationMode) — преобразует объект из detached в persistent, при этом у объекта обязательно должен быть заранее установлен Id. Данный метод предназначен для сохранения в БД объекта с заданным Id, чего не позволяют сделать persist() и merge(). Если объект с данным Id уже существует в БД, то поведение определяется согласно правилу из перечисления org.hibernate.ReplicationMode:
    ReplicationMode.IGNORE — ничего не меняется в базе.
    ReplicationMode.OVERWRITE — объект сохраняется в базу вместо существующего.
    ReplicationMode.LATEST_VERSION — в базе сохраняется объект с последней версией.
    ReplicationMode.EXCEPTION — генерирует исключение.
  • delete(Object) — удаляет объект из БД, иными словами, преобразует persistent в transient. Object может быть в любом статусе, главное, чтобы был установлен Id.
  • save(Object) — сохраняет объект в БД, генерируя новый Id, даже если он установлен. Object может быть в статусе transient или detached
  • update(Object) — обновляет объект в БД, преобразуя его в persistent (Object в статусе detached)
  • saveOrUpdate(Object) — вызывает save() или update()
  • refresh(Object) — обновляет detached-объект, выполнив select к БД, и преобразует его в persistent
  • get(Object.class, id) — получает из БД объект класса-сущности с определённым Id в статусе persistent

А теперь обратим внимание на аннотации @OneToMany и @ManyToOne в классах-сущностях. Параметр fetch в @OneToMany обозначает, когда загружать дочерние объекты. Может иметь одно из двух значений, указанных в перечислении javax.persistence.FetchType:

FetchType.EAGER — загружать коллекцию дочерних объектов сразу же, при загрузке родительских объектов.
FetchType.LAZY — загружать коллекцию дочерних объектов при первом обращении к ней (вызове get) — так называемая отложенная загрузка.

Параметр cascade обозначает, какие из методов интерфейса Session будут распространяться каскадно к ассоциированным сущностям. Например, в классе-сущности User для коллекции tasks укажем:

Тогда при выполнении session.persist(user) или session.merge(user) операции persist или merge будут применены ко всем объектам из tasks. Аналогично для остальных операций из перечисления javax.persistence.CascadeType. CascadeType.ALL применяет все операции из перечисления. Необходимо правильно настроить CascadeType, дабы не подгружать из базы кучу лишних ассоциированных объектов-сущностей.

4). Извлечение объектов из БД

Приведём простой пример:

Вместо метода session.get() можно использовать session.load(). Метод session.load() возвращает так называемый proxy-object. Proxy-object — это объект-посредник, через который мы можем взаимодействовать с реальным объектом в БД. Он расширяет функционал объекта-сущности. Взаимодействие с proxy-object полностью аналогично взаимодействию с объектом-сущностью. Proxy-object отличается от объекта-сущности тем, что при создании proxy-object не выполняется ни одного запроса к БД, т. е. Hibernate просто верит нам, что объект с данным Id существует в БД. Однако первый вызванный get или set у proxy-object сразу инициирует запрос select, и если объекта с данным Id нет в базе, то мы получим ObjectNotFoundException. Основное предназначение proxy-object — реализация отложенной загрузки.

Вызов user.getTasks() инициирует загрузку задач юзера из БД, так как в классе User для tasks установлен FetchType.LAZY.

LazyInitializationException

С параметром FetchType.LAZY нужно быть аккуратнее. Иногда при загрузке ассоциированных сущностей мы можем поймать исключение LazyInitializationException. В вышеуказанном коде во время вызова user.getTasks() user должен быть либо в статусе persistent, либо proxy.

Также LazyInitializationException может вызвать небольшое изменение в нашем коде:

Здесь теоретически всё верно. Но при попытке обращения к tasksList мы МОЖЕМ получить LazyInitializationException. Но в дебагере данный код отрабатывает верно. Почему? Потому, что user.getTasks() только возвращает ссылку на коллекцию, но не ждёт её загрузки. Не подождав, пока загрузятся данные, мы закрыли сессию. Выход — выполнять в транзакции, т. е.:

Выборка с условиями

А теперь приведём несколько простых примеров выборки данных с условиями. Для этого в Hibernate используются объекты типа org.hibernate.Criteria:

Здесь понятно, что мы выполняем select * from user where login=’login’. В метод add мы передаём объект типа Criterion, представляющий определённый критерий выборки. Класс org.hibernate.criterion.Restrictions предоставляет множество различных видов критериев. Параметр «login» обозначает название свойства класса-сущности, а не поля в таблице БД.
Приведём ещё пару примеров:

Здесь мы выбираем по содержимому свойства name класса-сущности Task. MatchMode.ANYWHERE означает, что нужно искать подстроку name в любом месте свойства «name».

б).
А здесь мы получаем 50 строк, начиная с 20-го номера в таблице.

5). Сохранение объектов

Давайте разберём несколько способов сохранения объекта-сущности в базу данных.

а). Создаём transient-object и сохраняем в базу:

Отметим несколько нюансов. Во-первых, сохранение в БД можно производить только в рамках транзакции. Вызов session.openTransaction() открывает для данной сессии новую транзакцию, а session.getTransaction().commit() её выполняет. Во-вторых, в метод task.setUser(user) мы передаём user в статусе detached. Можно передать и в статусе persistent.

Данный код выполнит (не считая получения user) 2 запроса — select nextval(‘task_task_id_seq’) и insert into task.
Вместо saveOrUpdate() можно выполнить save(), persist(), merge() — будет также 2 запроса. Вызов session.flush() применяет все изменения к БД, но, если честно, этот вызов здесь бесполезен, так как ничего не сохраняется в БД до commit(), который сам вызовет flush().

Помним, что если мы внутри транзакции что-то изменим в загруженном из БД объекте статуса persistent или proxy-object, то выполнится запрос update. Если task должен ссылаться на нового user, то делаем так:

Внимание: в классе Task для поля user должен быть установлен CascadeType.PERSIST, CascadeType.MERGE или CascadeType.ALL.

Если мы имеем на руках userId существующего в БД юзера, то нам не обязательно загружать объект User из БД, делая лишний select. Так как мы не можем присвоить ID юзера непосредственно свойству класса Task, нам нужно создать объект класса User с единственно заполненными userId. Естественно, это не может быть transient-object, поэтому здесь следует воспользоваться известным нам proxy-объектом.

б). Добавляем объект в коллекцию дочерних объектов:

В User для свойства tasks должен стоять CascadeType.ALL. Если стоит CascadeType.MERGE, то после user.getTasks().add(task) выполнить session.merge(user). Данный код выполнит 3 запроса — select * from user, select nextval(‘task_task_id_seq’) и insert into task

6). Удаление объектов

а). Можно удалить, создав transient-object:

Данный код удалит только task. Однако, если task — объект типа proxy, persistent или detached и в классе Task для поля user действует CascadeType.REMOVE, то из базы удалится также ассоциированный user. Если удалять юзера не нужно, выполнить что? Правильно, task.setUser(null)

б). Можно удалить и таким способом:

Данный код просто удаляет связь между task и user. Здесь мы применили новомодное лямбда-выражение. Объект task удалится из БД при одном условии — если изменить кое-что в классе-сущности User:

Параметр orphanRemoval = true указывает, что все объекты Task, которые не имеют ссылки на User, должны быть удалены из БД.

7). Декларативное управление транзакциями

Для декларативного управления транзакциями мы будем использовать Spring Framework. Управление транзакциями осуществляется через менеджер транзакций. Вместо вызовов session.openTransaction() и session.commit() используется аннотация @Transactional. В конфигурации приложения должно присутствовать следующее:

Здесь мы определили бин transactionManager, к которому привязан бин sessionFactory. Класс HibernateTransactionManager является реализацией общего интерфейса org.springframework.transaction.PlatformTransactionManager для SessionFactory библиотеки Hibernate. annotation-driven указывает менеджеру транзакций обрабатывать аннотацию @Transactional.

— Болтовня ничего не стоит. Покажите мне код. (Linus Torvalds)

Аннотация @Transactional указывает, что метод должен выполняться в транзакции. Менеджер транзакций открывает новую транзакцию и создаёт для неё экземпляр Session, который доступен через sessionFactory.getCurrentSession(). Все методы, которые вызываются в методе с данной аннотацией, также имеют доступ к этой транзакции, потому что экземпляр Session является переменной потока (ThreadLocal). Вызов sessionFactory.openSession() откроет совсем другую сессию, которая не связана с транзакцией.

Параметр rollbackFor указывает исключения, при выбросе которых должен быть произведён откат транзакции. Есть обратный параметр — noRollbackFor, указывающий, что все исключения, кроме перечисленных, приводят к откату транзакции.

Параметр propagation самый интересный. Он указывает принцип распространения транзакции. Может принимать любое значение из перечисления org.springframework.transaction.annotation.Propagation. Приведём пример:

Метод UserDao.getUserByLogin() также может быть помечен аннотацией @Transactional. И здесь параметр propagation определит поведение метода UserDao.getUserByLogin() относительно транзакции метода saveTask():

  • Propagation.REQUIRED — выполняться в существующей транзакции, если она есть, иначе создавать новую.
  • Propagation.MANDATORY — выполняться в существующей транзакции, если она есть, иначе генерировать исключение.
  • Propagation.SUPPORTS — выполняться в существующей транзакции, если она есть, иначе выполняться вне транзакции.
  • Propagation.NOT_SUPPORTED — всегда выполняться вне транзакции. Если есть существующая, то она будет остановлена.
  • Propagation.REQUIRES_NEW — всегда выполняться в новой независимой транзакции. Если есть существующая, то она будет остановлена до окончания выполнения новой транзакции.
  • Propagation.NESTED — если есть текущая транзакция, выполняться в новой, так называемой, вложенной транзакции. Если вложенная транзакция будет отменена, то это не повлияет на внешнюю транзакцию; если будет отменена внешняя транзакция, то будет отменена и вложенная. Если текущей транзакции нет, то просто создаётся новая.
  • Propagation.NEVER — всегда выполнять вне транзакции, при наличии существующей генерировать исключение.
Ну что ж, подведём итоги

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

Hibernate Session

Session interface is a single threaded object between Java application and the persistence layer. Session opens a single database connection when it is created, and holds onto it until the session is closed. It is mainly to offer CRUD operations on the persistent object which is loaded by Hibernate from the database.

More details, in hibernate, Session interface wraps a JDBC connection, holds a mandatory (first-level) cache of persistent objects, allows Hibernate to automatically persist objects that are modified, and allows Hibernate to implement functionality such as lazy-loading.

State of persistent object

Persistent objects should be in one of the following three states at a given point in time:

transient: A new instance of a persistent class which is not associated with a Session and has no representation in the database and no identifier value. (ex. Person p = new Person). You can make a transient instance persistent by associating it with a Session.

persistent: A persistent instance has a representation in the database, an identifier value and is associated with a Session.

detached: Once we close the Hibernate Session, the persistent instance will become a detached instance. But the reference of the object is still valid. You could continue to modify the object. These changes will not lost and will be inserted into database when associated with a Session which changes it back to persistent state.

Open a session

Different version of Hibernate has different way to do it. The following is for Hibernate 4.3 only

To open a session, it’s better to create an util class:

To use getCurrentSession() , it needs to add in hibernate.cfg.xml:

openSession vs getCurrentSession

openSession()
  1. We can use it when we decided to manage the Session our self.
  2. It does not try to store or pull the session from the current context. Just a brand new one.
  3. If we use this method, we need to flush() and close() the session. It does not flush and close() automatically.
getCurrentSession()

The “CurrentSession” refers to a Hibernate Session bound by Hibernate behind the scenes, to the transaction scope. It creates a brand new session if does not exist or uses an existing one if one already exists. It automatically configured with both auto-flush and auto-close attributes as true means Session will be automatically flushed and closed. It’s better to use getCurrentSession() method when our transaction runs long time or with multi calls of session.

save() results in an SQL INSERT. It persists the given transient instance, first assigning a generated identifier. In brief, it adds/saves a new entity into database.

But be careful here, save() does not guarantee the same, it returns an identifier, and if an INSERT has to be executed to get the identifier, this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context.

persist()

persist() also makes a transient instance persistent. However, it doesn’t guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen at flush time. It also guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries. This is useful in long-running conversations with an extended Session/persistence context.

load() and get()

load() and get() result in an SQL SELECT BY ID . It returns the persistent instance of the given entity class with the given identifier.( load() returna a “proxy”)

Different between load() and get()

load() returns a “proxy” without hitting the database (lazy loading). In Hibernate, proxy is an object with the given identifier value, its properties are not initialized yet, it just look like a temporary fake object. If no row found , it will throws an exception — ObjectNotFoundException.

get() always hits the database and returns the real object instead of a proxy. If no row found , it return null.

Which one to use

If I’m not sure whether the object exists or not, I use get() to avoid an exception. If I’m sure, I prefer load() .

update() and saveOrUpdate()

Which function will result in SQL UPDATE ? We could find update() or saveOrUpdate() . But we need to know firstly, there is no need to call these functions to do update. When we get()/load() a persistent object, and then call setters to modify something. After transaction commit() or session flush() . Database will be updated.

update()

So why we need update() ? In fact, it’s mainly used to updated a detached object which was ever a persistent object and now session is closed. When update() a detached object, it will become persistent again.

saveOrUpdate()

It means either save() or update() the given instance on the basis of identifier exists or not. When we are not sure whether the instance was ever persistent (so whether an identifier exists or not). USE IT! If the instance has an identifier, update() will be run to update it in databas. If no identifier, save() will be run to add an identifier and insert it into database.

merge()

merge() is also used to update a detached object. It copies the state of the given object onto the persistent object with the same identifier.

The difference with update() is that update() tries to reattach the instance, meaning that there is no other persistent object with the same identifier attached to the Session right now otherwise NonUniqueObjectException is thrown. merge() , however, just copies all values to a persistent instance in the Session (which will be loaded if it is not currently loaded). The input object is not changed. So merge is more general than update() , but may use more resources.

So if in this situation, we should use merge() , it needs to merge user1 with user2:

So here merge returns the same reference of user2.

delete()

delete() results in SQL DELETE

No ind() in current version! We must use query or criteria to achieve it.

Сессии и DAO классы в Hibernate

Есть маленький проектик работающий с БД. В качестве ORM решения выбран Hibernate 4.

Попутно обуздывая фреймворк, создал классы сущностей, связал аннотациями, использовал DAO pattern. Но: в имплементации ДАО классов в каждом изменяющем БД методе сессия открывалась и закрывалась прямо в методе (как и в этой туториал ссылочке http://javaxblog.ru/article/java-hibernate-1/). Пример

Но что-то подсказывает, что это как-то, мягко говоря, не правильно.
Порыв немного интернет, наткнулся на статейку (https://developer.jboss.org/wiki/GenericDataAccessObjects), где говорится, что ДАО имплементации не должны создавать сессию внутри, а на неё нужно лишь ссылаться. Если я правильно понял, ДАО имплементаций не должно волновать создание сессий.

You could also use constructor injection. How you set the Session and what scope this Session has is of no concern to the actual DAO implementation. A DAO should not control transactions or the Session scope.

Интересует вопрос опытных разработчиков: создавать ли сессию один раз на всё приложение и просто в сеттере давать ссылочку ДАО классам (при этом сессию не закрывать), или же в каждом методе ДАО класса создавать и закрывать сессию?

Жаль, что автор не нашёл время сам ответить на свой вопрос. Хоть я ни разу не опытный разработчик, попробую ответить на основании информации, которую нашёл в сети на текущий день.
На многих ресурсах рекомендуют использовать Hibernate в связке со Spring. Мне не нравится этот совет тем, что вводится лишняя «сущность». Человек учится пользоваться отвёрткой, а ему хотят всучить шуруповёрт. Да, вроде бы шуруповёрт круче, но и отвёрткой уметь пользоваться тоже не будет лишним.

Ручное открытие/закрытие сессии.
В первую очередь напрашивается такая структура взаимодействия: слой DAO содержит только основные (CRUD — create, read, update, delete) операции взаимодействия с базой данных; в бизнес-слой выносятся операции, которые можно (и нужно) объединять в транзакции.
Выглядит DAO-класс примерно так:

Сессия session создаётся в бизнес-слое и передаётся в конструктор DAO:

Недостаток метода очевиден — при большой нагрузке должен активно работать сборщик мусора, чтобы освобождать память от DAO- и сервисных объектов. Это осталось за кадром, но подразумевается, что также должен создаваться объект сервисного класса AdminServiceImpl . В конструкторе этот объект получает ссылку на объект типа SessionFactory .

Стратегия открытия сессии
Чтобы избавиться от постоянного создания dao — и сервисных объектов, нужен механизм создания сессии или получения текущей сессии в каждом из этих объектов независимо друг от друга. И тут на помощь приходят стратегии открытия-закрытия сессии. Рекомендую эту статью к прочтению. Допустим, что выбираем стратегию ManagedSessionContext — каждому потоку по отдельной сессии. Тогда для получения сессии можно будет использовать
Session session = sessionFactory.getCurrentSession();

Увы, сразу это не заработает. Чтобы заработало, нужно в hibernate.cfg.xml прописать
<property name=»current_session_context_class»>thread</property> .
Или второй способ — в конфигурацию hibernate добавить свойство
configuration.setProperty(«hibernate.current_session_context_class», «thread»);

Уже знакомый DAO-класс будет теперь выглядеть так:

Здесь DBService — абстрактный класс, содержащий ссылку на объект SessionFactory . Так выглядит функция getSessionFactory() :

А вот и переделанный сервисный класс:

Вот используемые функции из DBService:

А вот класс DaoFactory для получения инстанса ItemDAO :

Собственно, на этом, думаю, всё. Для тех, кто хочет пощупать код, вот ссылки на github:
— ручное управление сессией;
— управление при помощи ManagedSessionContext .

Hibernate – Сессии

Сессия используется для получения физического соединения с базой данных. Объект Session является легким и предназначен для реализации каждый раз, когда необходимо взаимодействие с базой данных. Постоянные объекты сохраняются и извлекаются через объект Session.

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

Экземпляры могут существовать в одном из следующих трех состояний в данный момент времени –

временный – новый экземпляр постоянного класса, который не связан с сеансом и не представлен в базе данных, а значение идентификатора не считается временным в Hibernate.

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

detached – после того, как мы закроем Hibernate Session, постоянный экземпляр станет отдельным экземпляром.

временный – новый экземпляр постоянного класса, который не связан с сеансом и не представлен в базе данных, а значение идентификатора не считается временным в Hibernate.

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

detached – после того, как мы закроем Hibernate Session, постоянный экземпляр станет отдельным экземпляром.

Экземпляр Session является сериализуемым, если его постоянные классы сериализуемы. Типичная транзакция должна использовать следующую идиому –

Если сеанс вызывает исключение, транзакция должна быть откатана, а сеанс должен быть отменен.

Методы интерфейса сеанса

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

Транзакция beginTransaction ()

Начните единицу работы и верните связанный объект транзакции.

void cancelQuery ()

Отмените выполнение текущего запроса.

void clear ()

Полностью очистить сессию.

Соединение закрыто ()

Завершите сеанс, освободив соединение JDBC и очистив.

Критерии createCriteria (Класс persistentClass)

Создайте новый экземпляр Criteria для данного класса сущности или суперкласса класса сущности.

Критерии createCriteria (String entityName)

Создайте новый экземпляр Criteria для данного имени объекта.

Сериализуемый getIdentifier (Объектный объект)

Вернуть значение идентификатора данного объекта, связанного с этим сеансом.

Запрос createFilter (Коллекция объектов, String queryString)

Создайте новый экземпляр Query для данной коллекции и строку фильтра.

Запрос createQuery (String queryString)

Создайте новый экземпляр Query для заданной строки запроса HQL.

SQLQuery createSQLQuery (String queryString)

Создайте новый экземпляр SQLQuery для данной строки запроса SQL.

void delete (объектный объект)

Удалите постоянный экземпляр из хранилища данных.

void delete (String entityName, Object object)

Удалите постоянный экземпляр из хранилища данных.

Сеанс get (String entityName, Serializable id)

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

SessionFactory getSessionFactory ()

Получить фабрику сеансов, которая создала этот сеанс.

void refresh (объектный объект)

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

Транзакция getTransaction ()

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

логическое isConnected ()

Проверьте, подключен ли сеанс в данный момент.

логическое isDirty ()

Содержит ли этот сеанс какие-либо изменения, которые должны быть синхронизированы с базой данных?

логическое isOpen ()

Проверьте, открыт ли сеанс.

Сериализуемое сохранение (объектный объект)

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

void saveOrUpdate (Объектный объект)

Сохраните (Object) или обновите (Object) данный экземпляр.

void update (Объектный объект)

Обновите постоянный экземпляр с помощью идентификатора данного отдельного экземпляра.

void update (String entityName, Object object)

Обновите постоянный экземпляр с помощью идентификатора данного отдельного экземпляра.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *