根据请求更改事务隔离级别

时间:2022-10-11 06:51:32

I am writing a little auction app, and it is very important that my bids are recorded with certainty. After all, the last couple seconds of the auction are critical moments for the buyers, and I can't risk them simultaneously bidding and having a race condition.

我正在写一个小小的拍卖应用程序,我的出价一定要被记录下来。毕竟,最后几秒钟的拍卖对买家来说是关键时刻,我不能冒险让他们同时出价和拥有比赛条件。

And of course, that's what transaction isolation is for. I can set my isolation level to serializeable, and we're all set.

当然,这就是事务隔离的作用。我可以将隔离级别设置为serializeable,我们都设置好了。

But what about all the other requests? If people are viewing profiles, or sending messages, these requests don't need anywhere near that kind of transaction isolation. A read committed isolation level is perfectly acceptable for those requests.

但是其他的请求呢?如果人们正在查看配置文件或发送消息,这些请求不需要任何类似的事务隔离。对于这些请求,读提交隔离级别是完全可以接受的。

I'm setting my transaction level as part of my hibernate property hibernate.connection.isolation, but I'd really like to be able to do something like session.setTransactionIsolation(newIsolation) per request.

我将事务级别设置为hibernate属性hibernate.connection的一部分。隔离,但是我真的希望能够对每个请求执行session.setTransactionIsolation(newIsolation)之类的操作。

4 个解决方案

#1


4  

Session session = getSession(dataSource, sessionFactory, Connection.TRANSACTION_SERIALIZABLE);

public Session getSession(DataSource dataSource, SessionFactory sessionFactory, int isolationLevel){

  // Get connection from current dataSource and set new isolation
  Connection connectionWithNewIsolation = dataSource.getConnection();
  connectionWithNewIsolation.setTransactionIsolation(isolationLevel);

  // Get session from current sessionFactory with the new isolation
  Session session = sessionFactory.openSession(connectionWithNewIsolation);

  // Hibernate 4.3
  //SessionFactory.openStatelessSession(Connection connection)
  // Hibernate 3.6
  //SessionFactory.openSession(Connection connection)
  //SessionFactory.openStatelessSession(Connection connection)

  return session;
}

#2


8  

If you're using Spring you can use something like this:

如果你用的是Spring,你可以这样使用:

@Transactional(isolation = Isolation.SERIALIZABLE)

and it works for the JpaTransactionManager. If you are using JtaTransactionManager the request-scope transaction isolation is not propagated, as this is the default JTA behavior.

它适用于JpaTransactionManager。如果使用JtaTransactionManager,则不会传播请求范围事务隔离,因为这是默认的JTA行为。

Because JTA doesn’t support transaction-scoped isolation levels, Spring offers the IsolationLevelDataSourceRouter to overcome this shortcoming when using application server JTA DataSources.

由于JTA不支持事务范围的隔离级别,Spring提供了IsolationLevelDataSourceRouter来克服使用应用服务器JTA数据源时的这一缺陷。

Because most DataSource implementations can only take a default transaction isolation level, we can have multiple such DataSources, each one serving connections for a specific transaction isolation level.

因为大多数数据源实现只能采用默认的事务隔离级别,所以我们可以有多个这样的数据源,每个数据源都为特定事务隔离级别的连接提供服务。

The logical transaction (e.g. @Transactional) isolation level setting is introspected by the IsolationLevelDataSourceRouter and the connection acquire request is therefore delegated to a specific DataSource implementation that can serve a JDBC Connection with the same transaction isolation level setting.

逻辑事务(例如,@Transactional)隔离级别设置是由隔离级别的数据源进行的,因此连接获取请求被委托给一个特定的数据源实现,该实现可以提供与相同事务隔离级别设置的JDBC连接。

So, even in JTA environments, the transaction isolation router can offer a vendor-independent solution for overriding the default database isolation level on a per transaction basis.

因此,即使在JTA环境中,事务隔离路由器也可以提供独立于供应商的解决方案,以便在每个事务的基础上覆盖默认的数据库隔离级别。

Java EE doesn't support method-level transaction isolation configuration.

Java EE不支持方法级事务隔离配置。

The SERIALIZABLE isolation level will protect you against non-repeatable reads and phantom reads, and even SERIALIZABLE doesn't protect you against lost updates across multiple-request logical transactions.

SERIALIZABLE隔离级别将保护您不受不可重复读取和幻象读取的影响,甚至连SERIALIZABLE都不会保护您不受跨多个请求逻辑事务丢失的更新的影响。

Optimistic locking scales better when using the detached entities (as of they were loaded when the logical transaction has started).

当使用分离的实体时(当逻辑事务开始时加载它们),乐观锁的伸缩性更好。

#3


2  

For this case, i will use Optimistic lock in your bids objects... the race condition will still occurs, but it will be detected when the transaction tries to commit the changes at your domain objects (throwing an exception if the version readed was updated by another thread).

对于这种情况,我将在您的出价对象中使用乐观锁……竞争条件仍然会发生,但是当事务试图在域对象上提交更改时将会被检测到(如果被另一个线程更新的版本会抛出异常)。

So any change on any bid object, will be almost serializable (i say "almost" because in order to be serializable, the failed transactions will need to be catched and retried somehow).

因此,对任何出价对象的任何更改,几乎都是可序列化的(我说“几乎”,因为为了可序列化,失败的事务需要被捕获并以某种方式重试)。

#4


0  

if setting isolation level per transaction fails, you can always serialize specific operation manually in your code (synchronized, semaphores etc). however keep it mind it's not scalable (single jvm, single operation, easy to be accidentally by-passed from other parts of code)

如果设置每个事务的隔离级别失败,您总是可以在代码中手动序列化特定的操作(同步、信号量等)。但是要注意它是不可伸缩的(单个jvm、单个操作、很容易从代码的其他部分意外传递)

#1


4  

Session session = getSession(dataSource, sessionFactory, Connection.TRANSACTION_SERIALIZABLE);

public Session getSession(DataSource dataSource, SessionFactory sessionFactory, int isolationLevel){

  // Get connection from current dataSource and set new isolation
  Connection connectionWithNewIsolation = dataSource.getConnection();
  connectionWithNewIsolation.setTransactionIsolation(isolationLevel);

  // Get session from current sessionFactory with the new isolation
  Session session = sessionFactory.openSession(connectionWithNewIsolation);

  // Hibernate 4.3
  //SessionFactory.openStatelessSession(Connection connection)
  // Hibernate 3.6
  //SessionFactory.openSession(Connection connection)
  //SessionFactory.openStatelessSession(Connection connection)

  return session;
}

#2


8  

If you're using Spring you can use something like this:

如果你用的是Spring,你可以这样使用:

@Transactional(isolation = Isolation.SERIALIZABLE)

and it works for the JpaTransactionManager. If you are using JtaTransactionManager the request-scope transaction isolation is not propagated, as this is the default JTA behavior.

它适用于JpaTransactionManager。如果使用JtaTransactionManager,则不会传播请求范围事务隔离,因为这是默认的JTA行为。

Because JTA doesn’t support transaction-scoped isolation levels, Spring offers the IsolationLevelDataSourceRouter to overcome this shortcoming when using application server JTA DataSources.

由于JTA不支持事务范围的隔离级别,Spring提供了IsolationLevelDataSourceRouter来克服使用应用服务器JTA数据源时的这一缺陷。

Because most DataSource implementations can only take a default transaction isolation level, we can have multiple such DataSources, each one serving connections for a specific transaction isolation level.

因为大多数数据源实现只能采用默认的事务隔离级别,所以我们可以有多个这样的数据源,每个数据源都为特定事务隔离级别的连接提供服务。

The logical transaction (e.g. @Transactional) isolation level setting is introspected by the IsolationLevelDataSourceRouter and the connection acquire request is therefore delegated to a specific DataSource implementation that can serve a JDBC Connection with the same transaction isolation level setting.

逻辑事务(例如,@Transactional)隔离级别设置是由隔离级别的数据源进行的,因此连接获取请求被委托给一个特定的数据源实现,该实现可以提供与相同事务隔离级别设置的JDBC连接。

So, even in JTA environments, the transaction isolation router can offer a vendor-independent solution for overriding the default database isolation level on a per transaction basis.

因此,即使在JTA环境中,事务隔离路由器也可以提供独立于供应商的解决方案,以便在每个事务的基础上覆盖默认的数据库隔离级别。

Java EE doesn't support method-level transaction isolation configuration.

Java EE不支持方法级事务隔离配置。

The SERIALIZABLE isolation level will protect you against non-repeatable reads and phantom reads, and even SERIALIZABLE doesn't protect you against lost updates across multiple-request logical transactions.

SERIALIZABLE隔离级别将保护您不受不可重复读取和幻象读取的影响,甚至连SERIALIZABLE都不会保护您不受跨多个请求逻辑事务丢失的更新的影响。

Optimistic locking scales better when using the detached entities (as of they were loaded when the logical transaction has started).

当使用分离的实体时(当逻辑事务开始时加载它们),乐观锁的伸缩性更好。

#3


2  

For this case, i will use Optimistic lock in your bids objects... the race condition will still occurs, but it will be detected when the transaction tries to commit the changes at your domain objects (throwing an exception if the version readed was updated by another thread).

对于这种情况,我将在您的出价对象中使用乐观锁……竞争条件仍然会发生,但是当事务试图在域对象上提交更改时将会被检测到(如果被另一个线程更新的版本会抛出异常)。

So any change on any bid object, will be almost serializable (i say "almost" because in order to be serializable, the failed transactions will need to be catched and retried somehow).

因此,对任何出价对象的任何更改,几乎都是可序列化的(我说“几乎”,因为为了可序列化,失败的事务需要被捕获并以某种方式重试)。

#4


0  

if setting isolation level per transaction fails, you can always serialize specific operation manually in your code (synchronized, semaphores etc). however keep it mind it's not scalable (single jvm, single operation, easy to be accidentally by-passed from other parts of code)

如果设置每个事务的隔离级别失败,您总是可以在代码中手动序列化特定的操作(同步、信号量等)。但是要注意它是不可伸缩的(单个jvm、单个操作、很容易从代码的其他部分意外传递)