Як synchronized
працює ключове слово Java
Коли ви додаєте synchronized
ключове слово до статичного методу, метод може викликатись лише одним потоком за один раз.
У вашому випадку кожен виклик методу:
- створити нове
SessionFactory
- створити нове
Session
- взяти сутність
- повернути суть об'єкта абоненту
Однак це були ваші вимоги:
- Я хочу, щоб це запобігало доступу до інформації до того самого екземпляра БД.
- запобігання
getObjectById
виклику для всіх класів, коли він викликається певним класом
Отже, навіть якщо getObjectById
метод є безпечним для потоків, реалізація є неправильною.
SessionFactory
Кращі практики
Це SessionFactory
безпечно для потоків, і це дуже дорогий об'єкт, який потрібно створити, оскільки він повинен розібрати класи сутностей та створити внутрішнє представлення метамоделі сутності.
Отже, не слід створювати SessionFactory
кожен getObjectById
виклик методу.
Натомість вам слід створити для нього одиночний екземпляр.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
Session
Завжди повинен бути закритий
Ви не закрили блок Session
в finally
блоці, і це може витікати ресурси бази даних, якщо буде викинуто виняток при завантаженні сутності.
Відповідно до Session.load
методу JavaDoc може викинути a, HibernateException
якщо об'єкт не можна знайти в базі даних.
Не слід використовувати цей метод, щоб визначити, чи існує екземпляр ( get()
замість цього використовувати ). Використовуйте це лише для отримання екземпляра, який, на вашу думку, існує, де неіснування було б фактичною помилкою.
Ось чому вам потрібно використовувати finally
блок для закриття Session
, як це:
public static synchronized Object getObjectById (Class objclass, Long id) {
Session session = null;
try {
session = sessionFactory.openSession();
return session.load(objclass, id);
} finally {
if(session != null) {
session.close();
}
}
}
Запобігання доступу до кількох потоків
У вашому випадку ви хотіли переконатися, що лише одна нитка отримує доступ до цієї конкретної сутності.
Але synchronized
ключове слово заважає getObjectById
одночасно викликати два потоки . Якщо два потоки викликають цей метод один за одним, у вас все одно будуть два потоки, використовуючи цю сутність.
Отже, якщо ви хочете заблокувати даний об'єкт бази даних, щоб жоден інший потік не міг його змінити, тоді вам потрібно використовувати блоки блоків.
synchronized
Ключове слово працює тільки в одній віртуальній машині Java. Якщо у вас є кілька веб-вузлів, це не завадить багатопотоковому доступу через декілька JVM.
Що вам потрібно зробити, це використовувати LockModeType.PESSIMISTIC_READ
абоLockModeType.PESSIMISTIC_WRITE
одночасно застосовувати зміни до БД, наприклад:
Session session = null;
EntityTransaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.getTransaction();
tx.begin();
Post post = session.find(
Post.class,
id,
LockModeType.LockModeType.PESSIMISTIC_READ
);
post.setTitle("High-Performance Java Perisstence");
tx.commit();
} catch(Exception e) {
LOGGER.error("Post entity could not be changed", e);
if(tx != null) {
tx.rollback();
}
} finally {
if(session != null) {
session.close();
}
}
Отже, ось що я зробив:
- Я створив нову
EntityTransaction
і розпочав нову транзакцію з базою даних
- Я завантажив
Post
об'єкт, тримаючи блокування на пов'язаному записі бази даних
- Я змінив
Post
організацію та здійснив транзакцію
- У разі
Exception
кинутості я повернув транзакцію назад
Для отримання більш детальної інформації про трансляції ACID та бази даних, також ознайомтесь із цією статтею .