ユーザー統計を管理するためのオブジェクトを含むセッション スコープ クラスがあります。ユーザーが (SSO を介して) ログインすると、アプリケーション スコープのメソッドがアクティブなセッションのテーブルをチェックします。セッションが見つかった場合は、テーブルのセッション ID を使用してセッションが無効になります。
セッション スコープ クラスの userStats テーブルに行が追加されます。
/**
* get all the info needed for collecting user stats, add userStats to the users session and save to userStats table
* this happens after session is created
* @param request
*/
private void createUserStats(HttpServletRequest request){
if (!this.sessionExists) {
this.userStats = new UserStats(this.user, request.getSession(true)
.getId(), System.getProperty("atcots_host_name"));
request.getSession().setAttribute("userstats", this.userStats);
Events.instance().raiseEvent("userBoundToSession", this.userStats);
this.sessionExists = true;
log.info("user " + this.user + " is now logged on");
// add this to the db
try {
this.saveUserStatsToDb();
} catch (Exception e) {
log.error("could not save " + this.userStats.getId().getPeoplesoftId() + " information to db");
e.printStackTrace();
}
}
}
ユーザーのセッションが破棄されると、この行はログオフ時間で更新されます。
説明も複製もできない理由により、過去 2 週間で 2 人のユーザーがログインして行をロックしました。その場合、そのユーザーによるデータベース呼び出しはすべて不可能になり、このユーザーはアプリケーションを事実上使用できなくなります。
[org.hibernate.util.JDBCExceptionReporter] (http-127.0.0.1-8180-3) SQL Error: 0, SQLState: null
2012-07-26 18:45:53,427 ERROR [org.hibernate.util.JDBCExceptionReporter] (http-127.0.0.1-8180-3) Transaction is not active: tx=TransactionImple < ac, BasicAction: -75805e7d:3300:5011c807:6a status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -75805e7d:3300:5011c807:6a status: ActionStatus.ABORT_ONLY >)
これらの統計の収集は重要ですが、生死に関わることではありません。情報が得られない場合は、あきらめて動かし続けたいと思います。しかし、それは起こっていません。何が起こっているかというと、entityManager がロールバックのトランザクションをマークしていて、その後の db 呼び出しが上記のエラーを返しているということです。私はもともとユーザーの統計をアプリケーションスコープで保存しました。そのため、行がロックされると、アプリケーション全体のentityManagerがロックされました(これはうまくいきませんでした)。メソッドをセッションスコープに移動すると、問題のあるユーザーのみがロックアウトされます。
I tried setting the entityManger to a lesser scope(I tried EVENT and METHOD):
((EntityManager) Component.getInstance("entityManager", ScopeType.EVENT)).persist(this.userStats);
((EntityManager) Component.getInstance("entityManager", ScopeType.EVENT)).flush();
これはdb呼び出しをまったく行いません。トランザクションを手動でロールバックしようとしましたが、喜びはありません。
会話スコープ レベルで使用されるデータを含むテーブルの行をロックすると、結果は壊滅的なものにはなりません。データは保存されませんが、回復します。
到着予定時刻:
AsynchronousEvent を発生させようとしました - これはローカルで動作しますが、リモート テスト サーバーにデプロイされます - これは奇妙です - 私は得る:
DEBUG [org.quartz.core.JobRunShell] (qtz_Worker-1) Calling execute on job DEFAULT.2d0badb3:139030aec6e:-7f34
INFO [com.mypkg.myapp.criteria.SessionCriteria] (qtz_Worker-1) observing predestroy for seam
DEBUG [com.mypkg.myapp.criteria.SessionCriteria] (qtz_Worker-1) destroy destroy destroy sessionCriteria
ERROR [org.jboss.seam.async.AsynchronousExceptionHandler] (qtz_Worker-1) Exeception thrown whilst executing asynchronous call
java.lang.IllegalArgumentException: attempt to create create event with null entity
at org.hibernate.event.PersistEvent.<init>(PersistEvent.java:45)
at org.hibernate.event.PersistEvent.<init>(PersistEvent.java:38)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
...
奇妙な点は、Quartz ハンドラを通過しているように見えることです。
ETA 再び:
それほど奇妙ではありませんが、Quartz を非同期ハンドラーとして設定しました。これは、ジョブのスケジューリング専用だと思いました。また、非同期メソッドはセッション コンテキストにアクセスできないため、実際に永続化するオブジェクトを保持するには、監視メソッドにパラメーターを追加する必要がありました。
@Observer("saveUserStatsEvent")
@Transactional
public void saveUserStatsToDb(UserStats userstats) throws Exception {
if(userstats != null){
log.debug("persisting userstats to db");
this.getEntityManager().persist(userstats);
this.getEntityManager().flush();
}
}
これから回復するにはどうすればよいですか?