hibernate事务(将一行读作inprog,写入其他表)(读取其他表,将行设置为notinprog)

时间:2021-05-18 09:43:34

I am new to hibernate and transactions.

我是hibernate和交易的新手。

I have a row in a table that marks it as in-progress state. I have a second table that is used to write rows that are to be received by the in-progress worker just before it wraps up, and this effectively adds to its worklist.

我在表中有一行将其标记为进行中状态。我有一个第二个表,用于写入正在进行的工作程序在它包装之前接收的行,这有效地添加到其工作列表中。

There are 2 transactions that are using these 2 tables:

有2个事务正在使用这两个表:

1) a transaction fetches the in-progress dummy row for the maximum sequence number column. When it sees this row, it must know that that row has been committed. (What is the minimum isolation?) Then it checks to see if the row's in-progress flag is true. If in-progress, it knows that there is another long-running thread (not a single transaction) that has already committed that row to in-progress, and it adds its new piece of data to an auxilliary table, expecting that the long-running thread will get/remove/process the rows from the auxilliary table and do something with them and finally set inprogress to false in a single atomic transaction.

1)事务获取最大序列号列的正在进行的虚拟行。当它看到这一行时,它必须知道该行已被提交。 (什么是最小隔离?)然后它检查行的进行中标志是否为真。如果正在进行中,它知道还有另一个长时间运行的线程(不是单个事务)已经将该行提交到进行中,并且它将新的数据添加到辅助表中,期望长 - 运行线程将获取/删除/处理辅助表中的行并对它们执行某些操作,最后在单个原子事务中将inprogress设置为false。

2) the second thread starts and sees that in-progress is committed to true upon its start. It does several pieces of work in separate transactions. Then it does one final atomic transaction: (1) read the auxilliary data that several of the thread 1(s) wrote to the second table, (2) removes them and processes them, (3) writes in-progress column of in-progress row to false.

2)第二个线程启动并看到正在进行的启动时提交为true。它在单独的事务中完成了几项工作。然后它执行一个最终的原子事务:(1)读取几个线程1(s)写入第二个表的辅助数据,(2)删除它们并处理它们,(3)写入in-进行中的列 - 进度行为false。

My first question is, for these 2 related transactions, what minimum isolation levels do I need to make them work properly in that when thread 2 finishes, it will have processed all the auxilliary data that thread 1 added to second table B when it saw the in-progess state.

我的第一个问题是,对于这两个相关的事务,我需要什么最小隔离级别才能使它们正常工作,因为当线程2完成时,它将处理线程1添加到第二个表B时看到的所有辅助数据。 in-progess state。

Also, I'm very concerned that when I use hibernate setter to set the in-progress state to false in thread 2), that I must do it BEFORE fetching, removing and processing the auxilliary data. And that, doing it first in the transaction, do I also have to flush the session to get hibernate to cause the isolation?

另外,我非常担心当我使用hibernate setter在线程2中将进行中状态设置为false时,我必须在获取,删除和处理辅助数据之前执行此操作。而且,在事务中首先执行此操作,是否还必须刷新会话以使hibernate导致隔离?

Thanks, Andy

1 个解决方案

#1


0  

It seems to me that the key is to lock the row holding your in-progress flag, essentially equivalent to synchronizing on it in Java terms. You should consistently do this as the first thing before (or at the same time as) reading other data. Using the read-committed isolation level is fine.

在我看来,关键是锁定持有正在进行的标志的行,本质上相当于用Java术语同步它。在读取其他数据之前(或同时),您应始终如一地执行此操作。使用读取提交的隔离级别很好。

You can lock the row by specifying LockMode.UPGRADE (or LockOptions.UPGRADE I think it's changed to in 3.5) to Hibernate when getting the row from a query or from the session. If you're using a native SQL query, you'll have to use your databases implementation (typically ... FOR UPDATE). e.g.:

您可以通过在从查询或会话中获取行时将LockMode.UPGRADE(或LockOptions.UPGRADE,我认为它已更改为3.5)指定为Hibernate来锁定行。如果您使用的是本机SQL查询,则必须使用数据库实现(通常为...... FOR UPDATE)。例如。:

StatusData status = (StatusData) session.get(StatusData.class, id, LockOptions.UPGRADE);

which Hibernate will use to produce SELECT s_.id, ... FROM status_data s_ WHERE s_id = ? FOR UPDATE OF s_ or the appropriate equivalent for your dialect (e.g. with(updlock,rowlock))

哪个Hibernate将用于生成SELECT s_.id,... FROM status_data s_ WHERE s_id =?更新s_或你的方言的相应等价物(例如(updlock,rowlock))

Istr you specify this in a Query too, so probably something like:

你也可以在查询中指定这个,所以可能是这样的:

StatusData status = (StatusData)
  session.getNamedQuery("Status.FindLatest")
         .setLockMode("status", LockMode.UPGRADE)
         .uniqueResult();

Once you have this row in this mode, any other code trying to perform the same query will block until you have completed your transaction- so you are now free to make changes to status or its dependent collections.

在此模式下拥有此行后,尝试执行相同查询的任何其他代码都将阻塞,直到您完成事务为止 - 因此您现在可以*更改状态或其依赖集合。

I assume you've found the documentation of using transactions with Hibernate? http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

我假设您已经找到了使用Hibernate进行事务的文档? http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

I have had good experiences with using declarative transaction boundaries. So a DAO/EJB/whatever to perform the database interaction, exposed via an interface, and a decorator to automatically begin/commit/rollback around all calls through that interface. Spring and J2EE containers provide infrastructure to do this stuff, although it is easy to do it by hand too. This makes it clear in the code which bits are inside a database transaction and which bits aren't. So if you do the equivalent of:

我在使用声明式事务边界方面有很好的经验。所以DAO / EJB /无论是执行数据库交互,通过接口公开,还是装饰器,都可以通过该接口自动开始/提交/回滚所有调用。 Spring和J2EE容器提供了基础设施来完成这些工作,尽管它也很容易手工完成。这使得在代码中清楚地表明哪些位在数据库事务中,哪些位不在。所以,如果你做相当于:

void finishProcessing() {
   Session session = sessionFactory.openSession();
   Transaction tx = session.beginTransaction();
   ThreadLocalSessionContext.bind(session);
   boolean committed = false;
   try {
       underlying.finishProcessing();
       tx.commit();
       committed = true;
   } finally {
       if (!committed) tx.rollback();
       session.close();
       ThreadLocalSessionContext.unbind(sessionFactory);
   }
}

In your underlying implementation of finishProcessing() you can simply get the status row, perform your other changes and return: the transaction will be committed (which implicitly flushes the session) and the session closed on the way out.

在finishProcessing()的底层实现中,您可以简单地获取状态行,执行其他更改并返回:事务将被提交(隐式刷新会话)并且会话在关闭时关闭。

#1


0  

It seems to me that the key is to lock the row holding your in-progress flag, essentially equivalent to synchronizing on it in Java terms. You should consistently do this as the first thing before (or at the same time as) reading other data. Using the read-committed isolation level is fine.

在我看来,关键是锁定持有正在进行的标志的行,本质上相当于用Java术语同步它。在读取其他数据之前(或同时),您应始终如一地执行此操作。使用读取提交的隔离级别很好。

You can lock the row by specifying LockMode.UPGRADE (or LockOptions.UPGRADE I think it's changed to in 3.5) to Hibernate when getting the row from a query or from the session. If you're using a native SQL query, you'll have to use your databases implementation (typically ... FOR UPDATE). e.g.:

您可以通过在从查询或会话中获取行时将LockMode.UPGRADE(或LockOptions.UPGRADE,我认为它已更改为3.5)指定为Hibernate来锁定行。如果您使用的是本机SQL查询,则必须使用数据库实现(通常为...... FOR UPDATE)。例如。:

StatusData status = (StatusData) session.get(StatusData.class, id, LockOptions.UPGRADE);

which Hibernate will use to produce SELECT s_.id, ... FROM status_data s_ WHERE s_id = ? FOR UPDATE OF s_ or the appropriate equivalent for your dialect (e.g. with(updlock,rowlock))

哪个Hibernate将用于生成SELECT s_.id,... FROM status_data s_ WHERE s_id =?更新s_或你的方言的相应等价物(例如(updlock,rowlock))

Istr you specify this in a Query too, so probably something like:

你也可以在查询中指定这个,所以可能是这样的:

StatusData status = (StatusData)
  session.getNamedQuery("Status.FindLatest")
         .setLockMode("status", LockMode.UPGRADE)
         .uniqueResult();

Once you have this row in this mode, any other code trying to perform the same query will block until you have completed your transaction- so you are now free to make changes to status or its dependent collections.

在此模式下拥有此行后,尝试执行相同查询的任何其他代码都将阻塞,直到您完成事务为止 - 因此您现在可以*更改状态或其依赖集合。

I assume you've found the documentation of using transactions with Hibernate? http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

我假设您已经找到了使用Hibernate进行事务的文档? http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

I have had good experiences with using declarative transaction boundaries. So a DAO/EJB/whatever to perform the database interaction, exposed via an interface, and a decorator to automatically begin/commit/rollback around all calls through that interface. Spring and J2EE containers provide infrastructure to do this stuff, although it is easy to do it by hand too. This makes it clear in the code which bits are inside a database transaction and which bits aren't. So if you do the equivalent of:

我在使用声明式事务边界方面有很好的经验。所以DAO / EJB /无论是执行数据库交互,通过接口公开,还是装饰器,都可以通过该接口自动开始/提交/回滚所有调用。 Spring和J2EE容器提供了基础设施来完成这些工作,尽管它也很容易手工完成。这使得在代码中清楚地表明哪些位在数据库事务中,哪些位不在。所以,如果你做相当于:

void finishProcessing() {
   Session session = sessionFactory.openSession();
   Transaction tx = session.beginTransaction();
   ThreadLocalSessionContext.bind(session);
   boolean committed = false;
   try {
       underlying.finishProcessing();
       tx.commit();
       committed = true;
   } finally {
       if (!committed) tx.rollback();
       session.close();
       ThreadLocalSessionContext.unbind(sessionFactory);
   }
}

In your underlying implementation of finishProcessing() you can simply get the status row, perform your other changes and return: the transaction will be committed (which implicitly flushes the session) and the session closed on the way out.

在finishProcessing()的底层实现中,您可以简单地获取状态行,执行其他更改并返回:事务将被提交(隐式刷新会话)并且会话在关闭时关闭。