Обновление Spring Boot 1.5 до 2.0 - невозможно выполнить UPDATE в транзакции только для чтения - PullRequest
4 голосов
/ 14 июня 2019

Обновление Spring Boot 1.5 до 2.1.5

При попытке сделать операцию repository.save (entity) выдает следующую ошибку:

Caused by: com.impossibl.postgres.jdbc.PGSQLSimpleException: cannot execute UPDATE in a read-only transaction

Мы используем интерфейс org.springframework.data.repositoryCrudRepository для выполнения операций.

1) @Transactional(readOnly = false), как я понял, установка режима «Только чтение» на «ложь» работает только как подсказка для подслоев, как я могу проверить и изменить другие слои?

@Service
public class ServiceImpl

    private final Repository repository;

    @Autowired
    public ServiceImpl(Repository repository) {
        this.repository = repository;
    }
@Transactional(readOnly = false)
public void operation(Entity entity){
    repository.save(entity);
}

А хранилище

public interface Repository extends CrudRepository<Entity, UUID>{

    @Query("select e from Entity e where lower(u.name) = lower(?1)")
    Entity findByName(String name);

}

build.gradle
------------

`dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.5.RELEASE")
}
`

```runtime("org.springframework.boot:spring-boot-properties-migrator")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-jersey")
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-jetty")
    compile("org.springframework.boot:spring-boot-starter-mail")
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile("org.quartz-scheduler:quartz:2.3.1")
    compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
    compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
    compile("com.fasterxml.woodstox:woodstox-core:5.2.1")
    compile("org.glassfish.jersey.media:jersey-media-multipart:2.28")
    compile("net.java.dev.msv:msv-core:2013.6.1")
    compile("com.impossibl.pgjdbc-ng:pgjdbc-ng:0.8.2")
    compile('org.apache.commons:commons-lang3:3.9')
    compile('commons-io:commons-io:2.6')
    compile('org.apache.commons:commons-compress:1.18')
    compile('org.apache.poi:poi-ooxml:4.1.0')
    compile('org.apache.xmlbeans:xmlbeans:3.1.0')
    compile('org.mitre.dsmiley.httpproxy:smiley-http-proxy-servlet:1.10')
    compile('com.monitorjbl:xlsx-streamer:2.1.0')
    compile('com.zaxxer:HikariCP:3.3.1')

application.properties

spring.datasource.driverClassName=com.impossibl.postgres.jdbc.PGDriver

spring.datasource.url=
spring.datasource.username=
spring.datasource.password=


spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.idle-timeout=10000

 # Set auto-commit = false, otherwise - Caused by: java.sql.SQLException: 
  Clobs require connection to be in manual-commit mode... 


spring.datasource.hikari.auto-commit=false

logging.level.ROOT=INFO
logging.level.org.springframework.orm.jpa=DEBUG
logging.level.org.springframework.transaction=DEBUG

Одна важная вещь заключается в том, что я добавил Auto-Commit в false в Hikari, в противном случае произойдет сбой с исключением, как это можно увидеть в комментарии.

Примечание: в некоторых темах предлагалось проверить соединение postgres

    show default_transaction_read_only;
     default_transaction_read_only 
    -------------------------------
     off

    SELECT pg_is_in_recovery();
     pg_is_in_recovery 
    -------------------
     f

Заранее спасибо.

Ответы [ 2 ]

6 голосов
/ 18 июня 2019
  1. Свойство readOnly по умолчанию равно false, поэтому никогда не следует использовать @Transactional(readOnly = false), вместо него используйте @Transactional.
  2. Когда вы помечаете некоторые методы или классы с помощью @Trasnacional Spring создает прокси этого класса для внедрения логики Transaction Manager . Он использует компонент, реализующий интерфейс org.springframework.transaction.PlatformTransactionManager
  3. В вашем конкретном случае будет создан компонент org.springframework.orm.jpa.JpaTransactionManager.
  4. Spring Boot использует Hibernate в качестве поставщика JPA по умолчанию, поэтому в конечном итоге вся логика транзакций будет влиять на Hibernate . Например. readOnly = true используется для отключения механизма «грязной проверки», который выполняет все операции UPDATE в Hibernate .
  5. По умолчанию Spring Transaction Manager создает новый Hibernate Session (новый переход), когда он вызывает маркер метода с @Transactional и Session is прикреплен к текущей теме. Таким образом, все последующие вызовы в текущем потоке будут использовать одну и ту же Session (и ту же транзакцию). Если вы не измените свойство propagation.
  6. Все это означает, что конфиги для транзакции устанавливаются, когда Spring вызывает метод @Transactional в первый раз, и эти конфиги используются для всех вызовов методов в одном потоке. См. Пример кода:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Service
public class ServiceA {

    @Transactional(readOnly = true)
    public void a() {
        boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
        System.out.println(isReadOnly);
    }
}
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ServiceB {
    private final ServiceA serviceA;

    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

    @Transactional
    public void b() {
        serviceA.a();
    }
}
  • serviceA.a() напечатает true
  • serviceB.b() напечатает false
1 голос
/ 19 июня 2019

См. Руководство по миграции Spring Boot 2.0 о Gradle и добавлении плагина управления зависимостями:

Плагин Spring Boot Gradle больше не применяет автоматически плагин управления зависимостями.Вместо этого плагин Spring Boot теперь реагирует на применяемый плагин управления зависимостями, импортируя правильную версию спецификации spring-boot-dependencies.Это дает вам больше контроля над тем, как и когда настраивается управление зависимостями.

Для большинства приложений достаточно применения плагина управления зависимостями:

apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management' // <-- add this to your build.gradle

Также вы можете удалить spring.datasource.type

Если вы использовали spring.datasource.type для принудительного использования Hikari в приложении на основе Tomcat, теперь вы можете удалить это переопределение.

Также обратите внимание, чтоминимальная версия Hibernate составляет 5,2

Также я вижу, что вы добавили spring-boot-properties-migrator, обратите внимание, что ее следует удалить после завершения настройки миграции

После завершения миграции, пожалуйста,обязательно удалите этот модуль из зависимостей вашего проекта.

...