SpringBoot事务隔离级别

时间:2020-02-24 09:57:23

标签: hibernate spring-boot transactions spring-data-jpa

我正在这个项目中尝试检查事务隔离。我从READ_UNCOMMITTED级别开始,它不起作用。 代码很简单。

主要班级

@SpringBootApplication
@EnableTransactionManagement
public class HibernateTransactionsLocksTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(HibernateTransactionsLocksTestApplication.class, args);
    }

}

控制器

    @RestController
    public class HomeController {

        private final AccountService accountService;

        public HomeController(AccountService accountService) {
            this.accountService = accountService;
        }

        @GetMapping("/updateAccount2RU")
        public String updateAccount2RU() throws InterruptedException {
            accountService.updateAccount2RU();
            return "done!";
        }

        @GetMapping("/update2Account2RU")
        public String update2Account2RU() throws InterruptedException {
            accountService.update2Account2RU();
            return "done!";
        }
}

服务

@Service
public class AccountService {

    private final AccountRepository accountRepository;

    public AccountService(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void updateAccount2RU() throws InterruptedException {
        Account a = accountRepository.findById(2).get();
        System.out.println("Account amount: " + a.getAmount());
        a.setAmount(a.getAmount()+1);
        accountRepository.save(a);
        Thread.currentThread().sleep(5000);
    }

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void update2Account2RU() throws InterruptedException {
        Account a = accountRepository.findById(2).get();
        System.out.println("Account amount: " + a.getAmount());
        a.setAmount(a.getAmount()+1);
        Thread.currentThread().sleep(5000);
    }

}

存储库是一个简单的SpringData存储库

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {

    @Transactional(propagation = Propagation.MANDATORY, isolation = Isolation.READ_UNCOMMITTED)
    Account findByName(String name);
}

application.properties

server.contextPath=/

spring.datasource.url=jdbc:mysql://localhost:3306/trasactions-locks-tests
spring.datasource.username=
spring.datasource.password=
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.MySQL5Dialect

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
#spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

spring.jpa.open-in-view=false

#Check transactions behaviour
logging.level.org.springframework.transaction.interceptor=TRACE

基本上,我在Chrome中打开2个标签,并访问updateAccount2RU(这将读取帐户并增加金额,并且线程应在唤醒和提交事务之前休眠5秒钟),与此同时,我访问了第二种方法update2Account2RU读取相同的帐户,并且金额是从第一种方法读取的金额,而不是从更新的方法读取的金额。

1 个答案:

答案 0 :(得分:0)

您很可能需要在第一种方法中使用accountRepository.save(a);

SQL更新通常由Hibernate缓冲,直到事务提交(即您的事务方法返回)之时为止。

因此,在T2读取记录时,没有待处理的未提交数据库更改。

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void updateAccount2RU() throws InterruptedException {
    Account a = accountRepository.findById(2).get();
    System.out.println("Account amount: " + a.getAmount());
    a.setAmount(a.getAmount()+1);

    // force explicit flush so T2 should now see the uncommitted change
    accountRepository.saveAndFlush(a);

    Thread.currentThread().sleep(5000);
}

请参阅:

https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/objectstate-flushing.html

Session有时会执行所需的SQL语句 使JDBC连接的状态与对象的状态同步 保存在内存中。默认情况下,刷新过程会在 以下几点

  • 在执行某些查询之前
  • 来自org.hibernate.Transaction.commit()
  • 来自Session.flush()