当前位置: 首页 > 知识库问答 >
问题:

Spring Boot JPA@transactional@service不更新,但controller中的@transactional更新

蒙华翰
2023-03-14

我有一个非常基本的Spring Boot/JPA stack应用程序,它有一个控制器、服务层和存储库,它不像我所理解的那样持久更新。

微不足道的实体:

java prettyprint-override">@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private String name;

  protected Customer() {}

  public Customer(String name) { this.name = name; }

  // standard getters,setters //
}

一个微不足道的存储库:

@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {}

一个简单的服务层:

// If the service is @Transactional and the controller is not, the update does NOT occur
@Transactional
@Service
public class CustomerService {

  private static final Logger LOG = getLogger(CustomerService.class);

  @Autowired
  private CustomerRepository customerRepository;

  boolean updateCustomerName(Long id, String name) {
    Customer customer = customerRepository.findOne(id);

    if (customer == null) { return false; }

    // Modifies the entity
    customer.setName(name);

    // No explicit save()

    return true;
  }
}

和一个REST控制器,它全部使用:

// If the controller is @Transactional and the service is not, the update occurs
@RestController
@RequestMapping("/mvc")
public class CustomerController {

  @Autowired
  private CustomerService customerService;

  @RequestMapping(path = "{id}", method = RequestMethod.PUT)
  public ResponseEntity updateCustomerName(@PathVariable Long id, @RequestParam("name") String name) {

    customerService.updateCustomerName(id,name);

    return ResponseEntity.noContent().build();
  }
}

我启用了SQL调试日志,并查看了selects、update等。

使用上面的代码:当服务方法被控制器调用时,修改的实体不持久化。SQL日志显示实体的select,但没有update

如果没有标记@transactional,则也不会更新

如果我将显式的customerRepository.save(customer)添加到服务方法中,那么也会发生更新。但我的理解是ORM应该自动保存修改过的持久实体。

我确信这个问题与web请求中的EntityManager生命周期有关,但我感到困惑。是否需要进行其他配置?

完整示例请访问https://github.com/monztech/so-41515160

编辑:这已经解决了,见下文。根据Spring规范,@transactional在package-private方法中不起作用,并且错误地没有将update service方法公有。

如果方法为public并且服务类具有@transactional批注,则将发生更新。

不过,我还有另一个问题。为什么@transactional注释是必需的?(没有它就不会发生更新)实体管理器不应该仍然保持对象吗,因为Spring使用了视图中的open session机制,而不依赖于任何事务?

共有1个答案

薛泰
2023-03-14

使updateCustomerName方法公开。

 类似资料:
  • Spring V4.2.5发行版 Hibernate V5.1.0.final 我有一个Junit测试方法,它执行加载、更新属性并调用。 在方法签名中添加会阻止执行更新SQL(日志中没有生成SQL)。 删除,将生成更新SQL,并更新数据库。 实体是使用Netbeans的实体类从数据库自动生成的。 主实体与FetchType.Eager有一对一的关系,与FetchType.Eager有一对多的关系(

  • @Transactional标记是最近添加的。所以不确定它是否像预期的那样工作。 代码: 服务类别:

  • 问题内容: 考虑一下我有一个方法以ActiveRecord模式样式执行一些工作和日志记录机制: 在失败的情况下,我想保留一条错误消息,但是如果我抛出异常,catch子句中的事务将被回滚并且我的LogEntry将不会保留。我看到的唯一方法是手动调用after 。 有没有更干净的解决方案来执行此操作? 谢谢。 UPD: 由于我有一个执行持久化的静态方法,因此我需要对接受的答案应用以下技巧: 问题答案:

  • 但获得以下异常: 我搜索了一下,在SO上找到了类似的问题,解决方法如下: 这就解决了问题。但在该解决方案中,手动开始和提交事务会有很多麻烦。 请帮帮忙。

  • 在我的代码中,服务方法savePerson被注释为@Transactional。在这个方法中,Person实体被持久化,并且在中间故意抛出运行时异常。我支持不提交事务,但Person实体将保留在数据库中。。。。回滚不起作用,我不知道为什么。 这是我的Hibernate配置: 这是我的服务: 刀

  • 当我更新Service Worker时,我关闭并重新打开页面,并获得新的Service Worker已安装并激活的控制台日志,旧的缓存已被删除。但是,列出要添加到缓存中的文件不会再次从服务器获取,它们是几小时前的旧版本。没有办法让它更新文件,除非清除Chrome开发工具中的存储。 安装新版本时,如何让我的服务人员使用新文件填充其缓存? 例如,当服务人员更新时,“stylesheet.css”仍然是