Hibernate 从异步方法重复调用em.merge会锁定数据库表
我正在使用JBoss/Wildfly 7.1中的Java持久性API与MSSQL数据库进行接口。我有一个长期运行的异步函数,它定期插入和更新表,但每次更新之间有几秒钟的时间。当这个函数运行时,表在事务中被锁定,我无法从Java应用程序内部或外部查询表。下面是我如何实现DAO的示例:Hibernate 从异步方法重复调用em.merge会锁定数据库表,hibernate,jpa,transactions,Hibernate,Jpa,Transactions,我正在使用JBoss/Wildfly 7.1中的Java持久性API与MSSQL数据库进行接口。我有一个长期运行的异步函数,它定期插入和更新表,但每次更新之间有几秒钟的时间。当这个函数运行时,表在事务中被锁定,我无法从Java应用程序内部或外部查询表。下面是我如何实现DAO的示例: @Stateless class Dao { @PersistenceContext(unitName = "persistenceUnit") private EntityManager em;
@Stateless
class Dao {
@PersistenceContext(unitName = "persistenceUnit")
private EntityManager em;
public void mergeEntity(Entity e){
em.merge(e);
}
public Entity getEntity(int id){
return em.find(Entity.class,id);
}
}
class Service {
@Inject
private Dao dao;
private void updateEntity(int id){
Entity e = dao.getEntity(id)
//do update logic
dao.mergeEntity(e);
}
}
我还尝试为mergeEntity
方法请求新事务:
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void mergeEntity(Entity e){
em.merge(e);
}
当我这样做时,合并永远不会执行,操作只是挂起。为Hibernate打开跟踪日志记录并没有显示任何表明问题的信息。在Hibernate不主动修改表时,我能做些什么来防止它锁定表?除了MySQL(使用可重复读取)之外,大多数关系数据库系统的默认隔离级别都是读取提交的。所有数据库都允许您设置默认事务隔离级别
您可以尝试使用READ_UNCOMMITTED来绕过长期运行的更新问题。使用Hibernate,意味着设置:
<property name="hibernate.connection.isolation">1</property>
1
除了MySQL(它使用可重复读取),大多数关系数据库系统的默认隔离级别都是读取提交的。所有数据库都允许您设置默认事务隔离级别
您可以尝试使用READ_UNCOMMITTED来绕过长期运行的更新问题。使用Hibernate,意味着设置:
<property name="hibernate.connection.isolation">1</property>
1
由于服务被注入到一个总体EJB中,因此从getEntity调用开始,事务似乎一直处于打开状态。放置@TransactionaAttribute(TransactionaAttribute.REQUIRES\u NEW)时,另一个事务从未关闭,因此合并无法打开新事务。通过在调用getEntity方法时将@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)放在getEntity方法上,事务中将不会考虑该连接。这样,当调用merge方法时,容器就可以自由地为合并打开一个新事务。由于服务被注入到一个总体EJB中,因此从getEntity调用开始,事务似乎一直处于打开状态。放置@TransactionaAttribute(TransactionaAttribute.REQUIRES\u NEW)时,另一个事务从未关闭,因此合并无法打开新事务。通过在调用getEntity方法时将@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)放在getEntity方法上,事务中将不会考虑该连接。这样,当调用合并方法时,容器就可以自由地为合并打开一个新事务。获取线程转储以找出“卡住”的内容和确切位置,并打开SQL日志记录,以便查看执行的内容可能导致锁定。获取线程转储以找出“卡住”的内容和确切位置,并打开SQL日志记录,以便您可以查看执行的哪些操作可能导致锁定。