春季交易

时间:2016-09-10 10:29:29

标签: java spring spring-mvc spring-rest

我是Spring新手并对交易有疑问。

我知道每个http请求都有一个servlet线程,它有自己的堆栈。据我所知,所有局部变量和方法都驻留在堆栈上。因此,如果我有一个方法public void A();,那么servlet线程A和线程B都在其堆栈中有一个函数的副本。

现在如果我使用@Transactional(propagation=Propagation.REQUIRED ,timeout=1,isolation=Isolation.READ_COMMITTED)注释方法,那么我想知道以下几点:

  1. 每个线程A和线程B是否都有自己的堆栈并独立工作?

  2. 如果线程A正在更新某些内容而B正在读取某些东西,因为在不同的堆栈中,隔离是否有效?或者B将读取数据而不包含有关线程A?

  3. 的任何信息

    我想通过图表了解这一点,以便我能理解端到端的工作原理是什么?

3 个答案:

答案 0 :(得分:1)

线程B只会在线程A的事务完成后看到线程A完成的数据库修改。

线程B仍然可以从数据库中读取内容,然后线程A更新数据库中的内容并提交,然后线程B覆盖A写的线程。

为避免这种情况,您需要在数据库上使用某种类型的锁定,或使用更严格的隔离级别(但这会带来高性能损失,因为数据库通常需要执行大量锁定才能实现更严格的隔离级别)

答案 1 :(得分:1)

每个线程都有自己的堆栈,你就在这里。但他们没有方法的副本。方法只是一系列操作。但是他们在这个方法中有变量的副本(局部变量)。

谈到隔离级别,实际上它与线程和堆栈无关。它指的是数据库隔离级别概念。 Spring会要求您的数据库将该级别用于数据库事务。 PostreSQL有一个很好的doc page解释事务隔离。

所以在这里询问线程如何看到彼此并不完全正确,因为从数据的角度来看,他们看到了从数据库中获得的内容。并且数据库相应地返回当前事务隔离级别的数据。每个线程都会启动自己的事务,即它创建一个与数据库的新连接,并告诉它开始一个新的事务。

实施例

要了解幕后发生的事情,这里有一个例子。假设你有这样的方法:

@Transactional
public Person getPerson(int id) {
    Person person = em.find(Person.class, id);
    return person;
}

以下是每一行Spring引擎盖下的内容:

@Transactional
public Person getPerson(int id) {
// SQL sent to the database:
// Begin transaction

Person person = em.find(Person.class, id);
// SQL sent to the database:
// select p from person p where p.id = id
// the data from the database then gets converted to Java Person class

return person;
}
// after end of the method Spring automatically commits the transaction (not always, it depends on the `propagation` setting)
// SQL sent to the database:
// commit

请阅读PostgreSQL文档,深入解释事务隔离。 Java线程只接收与之相关的数据。

答案 2 :(得分:0)

Brifely:

  1. B将读取数据,但不包含有关线程A
  2. 的任何信息

    现在为什么这样?在servlet环境中,你有一个或多个servlet和类级别的所有数据,因此在doHttp方法之外共享相同的数据,servlet不是线程安全的。

    但当然,方法中的数据是线程安全的,因为每个方法调用都是一个调用函数,并且有一个用于提供方法请求的线程,并且它有自己的堆栈。

    但是如果你有两个并发的方法调用,并且由于这个原因在两个独立的线程中,事务将是不一样的,因为thrad本地不一样并且不共享相同的db的immage它是自然的如果你考虑JPA,persistanceContext是存储在threadlocal中的第一级缓存。我的建议是使用更高级别的事务隔离来缓解可能的问题

    我希望它可以帮到你