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
getObjectById
dipanggil untuk semua kelas ketika dipanggil oleh kelas tertentu
Jadi, bahkan jika getObjectById
metodenya aman, implementasinya salah.
SessionFactory
praktik terbaik
Ini SessionFactory
adalah 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 SessionFactory
pada setiap getObjectById
pemanggilan metode.
Sebagai gantinya, Anda harus membuat contoh tunggal untuk itu.
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
The Session
harus selalu tertutup
Anda tidak menutup Session
dalam finally
blok, dan ini bisa membocorkan sumber daya basis data jika pengecualian dilemparkan saat memuat entitas.
Menurut Session.load
metode JavaDoc mungkin membuang HibernateException
jika 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 finally
blok 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 synchronized
kata kunci hanya mencegah dua utas memanggil getObjectById
secara 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 synchronized
kunci 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_READ
atauLockModeType.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
EntityTransaction
dan memulai transaksi basis data baru
- Saya memuat
Post
entitas sambil memegang kunci pada catatan database terkait
- Saya mengubah
Post
entitas dan melakukan transaksi
- Dalam kasus
Exception
pelemparan, saya memutar kembali transaksi
Untuk detail lebih lanjut tentang ACID dan transaksi basis data, lihat artikel ini juga.