【问题标题】:How do avoid read-only transaction error when reading an entity and then save an entity using Spring Data repositories in a @RestController?如何在读取实体时避免只读事务错误,然后使用 @RestController 中的 Spring Data 存储库保存实体?
【发布时间】:2016-11-04 07:38:00
【问题描述】:

在 Spring @RestController 方法中,我尝试在使用 Spring Data CrudRepository 保存实体之前先检查实体是否存在,以便在调用 PUT 到不存在的子资源时返回 404 Not Found 响应存在。如果实体存在,它将尝试保存调用 myObjectDao.save(myObject) 但我收到以下错误:

原因:java.sql.SQLException:连接是只读的。查询 不允许导致数据修改 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996) 在 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:935) 在 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:924) 在 com.mysql.jdbc.SQLError.createSQLException(SQLError.java:870) 在 com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2108) 在 com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2077) 在 com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2062) 在 org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2578)

这是我的存储库和控制器:

public interface MyObjectDao extends CrudRepository<MyObject, Integer> {
}

@RestController
@RequestMapping("my-object")
public class MyObjectRestController {

    @Autowired
    private MyObjectDao myObjectDao;

    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    public MyObject update(@PathVariable(value = "id") Integer id,
            @RequestBody @Valid MyObject myObject) {

        if (!myObjectDao.exists(id)) {
            throw new ResourceNotFoundException(String.format("Entity with id %s cannot be found.", id));
        }
        MyObject.setId(id);
        return myObjectDao.save(myObject);
    }

似乎一旦调用 myObjectDao.exists(id) 并重用该事务进行保存,Spring 就会将该事务标记为只读。如何检查实体是否存在然后保存而不出现此错误?谢谢!

【问题讨论】:

  • 需要你的 dao 代码才能有更好的洞察力。
  • 我的道代码在那里。它使用 Spring Data 并且是 MyObjectDao 接口,Spring 在后台提供了实现。
  • 我正在使用 org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter 但我认为这与它没有任何关系。
  • 如果您没有设置事务配置,那么 OpenEntityManagerInViewFilter 可能就是造成这种情况的原因。如果没有设置事务配置,它会以只读执行模式绑定 JPA 实体管理器。来自 javadoc:它适用于通过 TransactionManager 或 JtaTransactionManager 进行的服务层事务以及非事务性只读执行
  • 我将其定义为事务管理器:

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


【解决方案1】:

如何将@Transactional 直接添加到update 方法以声明将传播到existssave 的非只读事务(假设您正在使用声明性事务管理)?

【讨论】:

  • 我已经尝试过那里和存储库界面,甚至在控制器的顶部作为只读假,也重新部署,没有任何影响!
  • @dukethrash 可能是死路一条,但您使用的是什么 mysql 连接器版本? bugs.mysql.com/bug.php?id=38747
  • 我正在使用 mysql-connector-java 5.1.33,您提供的链接显示该错误已在 5.1.7 中修复。
猜你喜欢
  • 1970-01-01
  • 2019-11-03
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2020-04-12
相关资源
最近更新 更多