どのようにsynchronized
Javaのキーワード作品
synchronized
静的メソッドにキーワードを追加すると、そのメソッドは一度に1つのスレッドからのみ呼び出すことができます。
あなたの場合、すべてのメソッド呼び出しは次のようになります:
- 新しいを作成します
SessionFactory
- 新しいを作成します
Session
- エンティティをフェッチする
- エンティティを呼び出し元に返す
ただし、これらはあなたの要件でした:
- これにより、同じDBインスタンスへの情報へのアクセスを防ぐことができます。
- 防止は、
getObjectById
それが特定のクラスによって呼び出されたときに、すべてのクラスのために呼び出されています
したがって、getObjectById
メソッドがスレッドセーフであっても、実装は間違っています。
SessionFactory
ベストプラクティス
の SessionFactory
スレッドセーフであり、それはそれはエンティティクラスを解析し、内部実体のメタモデル表現を構築する必要があるとして作成するには、非常に高価な物です。
したがって、SessionFactory
すべてを作成する必要はありませんgetObjectById
メソッド呼び出しでを。
代わりに、そのためのシングルトンインスタンスを作成する必要があります。
private static final SessionFactory sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
の Session
必ず閉じる必要があります
あなたはで閉じませんでしSession
たfinally
ブロックたため、エンティティの読み込み中に例外がスローされた場合、データベースリソースがリークする可能性があります。
Session.load
メソッドによると、HibernateException
エンティティがデータベースで見つからない場合、JavaDocはをスローする可能性があります。
このメソッドを使用してインスタンスが存在するかどうかを判断しないでください(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();
}
}
}
マルチスレッドアクセスの防止
あなたの場合、1つのスレッドだけがその特定のエンティティにアクセスできるようにする必要がありました。
ただし、このsynchronized
キーワードは、2つのスレッドがgetObjectById
同時にです。2つのスレッドがこのメソッドを順番に呼び出す場合でも、このエンティティを使用する2つのスレッドがあります。
したがって、他のスレッドがオブジェクトを変更できないように特定のデータベースオブジェクトをロックする場合は、データベースロックを使用する必要があります。
synchronized
キーワードは、単一のJVMで動作します。複数のWebノードがある場合、これは複数のJVMにわたるマルチスレッドアクセスを妨げません。
あなたがする必要があるのは、次のように、DBに変更を適用する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とデータベーストランザクションの詳細については、こちらの記事もご覧ください。