postgresql - 从 Spring Boot 1.5 升级到 2.0 - 无法在只读事务中执行更新

标签 postgresql hibernate spring-boot spring-data-jpa hikaricp

将 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 接口(interface)来执行操作。

1) @Transactional(readOnly = false),据我所知,将只读模式设置为 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')

应用程序属性

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

一件重要的事情是我在 Hikari 中将自动提交添加为 false,否则它会失败并出现异常,因为它可以在评论中看到。

注意:在某些线程中建议检查 postgres 连接

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

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

提前致谢。

最佳答案

  1. 属性 readOnly 默认为 false,所以你不应该使用 @Transactional(readOnly = false),使用 @Transactional 代替。
  2. 当您使用 @Transactional 标记某些方法或类时,Spring 会创建该类的代理以注入(inject) Transaction Manager 的逻辑。它使用一个实现接口(interface) org.springframework.transaction.PlatformTransactionManager
  3. 的 bean
  4. 在您的特定情况下,将创建 org.springframework.orm.jpa.JpaTransactionManager 的 bean。
  5. Spring Boot 使用 Hibernate 作为默认的 JPA 提供程序,因此最终所有事务逻辑都会影响 Hibernate .例如。 readOnly = true 用于禁用在 Hibernate 中执行所有更新操作的“脏检查”机制。
  6. 默认情况下,Spring Transaction Manager 在使用 @Transactional 调用方法标记时创建一个新的 Hibernate Session(新转换)并且没有 session 附加到当前线程。因此当前线程中的所有后续调用都将使用相同的 Session(和相同的事务)。除非您更改 propagation 属性。
  7. 这一切都意味着 事务的配置是在 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

关于postgresql - 从 Spring Boot 1.5 升级到 2.0 - 无法在只读事务中执行更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56599049/

相关文章:

postgresql - Dockerfile ENV变量不被接受

java - 使用 JPA 规范在 PostgreSQL jsonb 列中的所有值中搜索

postgresql - 尝试使用 OSX Snow Leopard (10.6.8) 在 Heroku 上启动 psql 时出现段错误

postgresql - Postgres : Whether to use oid or byte array

java - java中使用dao类获取行的异常

java - 使用 ImprovedNamingStrategy 创建表时出错

java - SpringBoot OAuth2 自定义异常响应

java - JSP 正在下载而不是渲染

java - maven 添加依赖时的问题

java - ArrayList 项和 hibernate 的问题