Bagaimana synchronized kerja kata kunci Java
Ketika Anda menambahkan synchronized kata kunci ke metode statis, metode ini hanya dapat dipanggil dengan utas tunggal setiap kali.
Dalam kasus Anda, setiap pemanggilan metode akan:
- buat yang baru
SessionFactory
- buat yang baru
Session
- ambil entitasnya
- mengembalikan entitas kembali ke pemanggil
Namun, ini adalah persyaratan Anda:
- Saya ingin ini mencegah akses ke info ke instance DB yang sama.
- mencegah
getObjectByIddipanggil untuk semua kelas ketika dipanggil oleh kelas tertentu
Jadi, bahkan jika getObjectByIdmetodenya aman, implementasinya salah.
SessionFactory praktik terbaik
Ini SessionFactoryadalah thread-safe, dan ini adalah objek yang sangat mahal untuk dibuat karena perlu mengurai kelas entitas dan membangun representasi metamodel entitas internal.
Jadi, Anda tidak harus membuat SessionFactorypada setiap getObjectByIdpemanggilan metode.
Sebagai gantinya, Anda harus membuat contoh tunggal untuk itu.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
The Sessionharus selalu tertutup
Anda tidak menutup Sessiondalam finallyblok, dan ini bisa membocorkan sumber daya basis data jika pengecualian dilemparkan saat memuat entitas.
Menurut Session.loadmetode JavaDoc mungkin membuang HibernateExceptionjika entitas tidak dapat ditemukan dalam database.
Anda sebaiknya tidak menggunakan metode ini untuk menentukan apakah ada instance (gunakan get()saja). Gunakan ini hanya untuk mengambil contoh yang Anda anggap ada, di mana ketidakberadaan akan menjadi kesalahan aktual.
Itu sebabnya Anda perlu menggunakan finallyblok untuk menutup Session, seperti ini:
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();
}
}
}
Mencegah akses multi-utas
Dalam kasus Anda, Anda ingin memastikan hanya satu utas yang mendapatkan akses ke entitas tertentu.
Tetapi synchronizedkata kunci hanya mencegah dua utas memanggil getObjectByIdsecara bersamaan. Jika kedua utas memanggil metode ini satu demi satu, Anda masih akan memiliki dua utas menggunakan entitas ini.
Jadi, jika Anda ingin mengunci objek database tertentu sehingga tidak ada utas lain yang dapat memodifikasinya, maka Anda perlu menggunakan kunci basis data.
Kata synchronizedkunci hanya berfungsi dalam JVM tunggal. Jika Anda memiliki beberapa web node, ini tidak akan mencegah akses multi-thread di beberapa JVM.
Yang perlu Anda lakukan adalah menggunakan LockModeType.PESSIMISTIC_READatauLockModeType.PESSIMISTIC_WRITE saat menerapkan perubahan pada DB, seperti ini:
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();
}
}
Jadi, inilah yang saya lakukan:
- Saya membuat yang baru
EntityTransactiondan memulai transaksi basis data baru
- Saya memuat
Postentitas sambil memegang kunci pada catatan database terkait
- Saya mengubah
Postentitas dan melakukan transaksi
- Dalam kasus
Exceptionpelemparan, saya memutar kembali transaksi
Untuk detail lebih lanjut tentang ACID dan transaksi basis data, lihat artikel ini juga.