Oracle db表锁定行和entityManager状态
我有一个会话范围的类,它包含一个用于管理用户统计信息的对象。当用户登录(通过SSO)时,应用程序范围的方法会检查表中是否有活动会话-如果发现任何活动会话,则使用表中的会话id使会话无效 将一行添加到会话作用域类中的userStats表中:Oracle db表锁定行和entityManager状态,oracle,hibernate,seam,entitymanager,seam2,Oracle,Hibernate,Seam,Entitymanager,Seam2,我有一个会话范围的类,它包含一个用于管理用户统计信息的对象。当用户登录(通过SSO)时,应用程序范围的方法会检查表中是否有活动会话-如果发现任何活动会话,则使用表中的会话id使会话无效 将一行添加到会话作用域类中的userStats表中: /** * get all the info needed for collecting user stats, add userStats to the users session and save to userStats table
/**
* 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个用户登录并锁定了该行。当这种情况发生时,该用户的任何数据库调用都不再可能,并且该应用程序实际上对此用户不可用
[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 >)
这根本不会进行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)
...
如何从中恢复?首先,在
组件中指定一个作用域。getInstance()
不会在指定的作用域中创建组件EntityManager
实例始终位于对话上下文中(无论是临时的还是长期运行的)。getInstance()
的scope
参数的唯一目的是提示组件应该在其中的上下文,以避免在所有上下文中进行昂贵的搜索(如果不指定上下文或指定错误的上下文,就会发生这种情况)
由于前面的错误,事务被标记为回滚。如果entityManager无论如何都要提交,那么它将不是事务性的(事实上,事务保证在发生错误时不会保留任何内容)。如果要将登录事务与统计数据收集隔离开来,最简单的解决方案是在异步事件中执行saveUserStatsToDb
方法(事务绑定到线程,因此使用不同的线程可以确保在单独的事务中处理事件)
大概是这样的:
@Observer("saveUserStatsEvent")
@Transactional
public void saveUserStatsToDb(UserStats stats) {
((EntityManager)Component.getInstance("entityManager")).persist(stats);
}
在您的createUserStats
方法中:
Events.instance().raiseAsynchronousEvent("saveUserStatsEvent", this.userStats);
然而,这只是通过将交易一分为二来规避问题。你真正想解决的是问题根源的锁定条件。Thanx关于回复,我更新了我原来的帖子。我确实解决了锁定条件,但我仍然需要找到一种方法来解决这个问题,我在收集涉及持久性的异常数据时也遇到了同样的问题。
@Observer("saveUserStatsEvent")
@Transactional
public void saveUserStatsToDb(UserStats stats) {
((EntityManager)Component.getInstance("entityManager")).persist(stats);
}
Events.instance().raiseAsynchronousEvent("saveUserStatsEvent", this.userStats);