Як 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 та бази даних, також ознайомтесь із цією статтею .