我有一个非常基本的Spring Boot / JPA堆栈应用程序,它有一个控制器,服务层和存储库,根据我的理解,它不会保留更新。
一个微不足道的实体:
@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();
}
}
这些是通过简单的单行SpringBootApplication
我启用了SQL调试日志,并查看选择,更新等
使用上面的代码:当控制器调用服务方法时,修改后的实体不持久化。 SQL日志显示实体的select
,但不显示update
。
如果没有标记@Transactional
但是,只需将@Transactional
注释从服务类移动到控制器类,SQL update
就会发生。
如果我向服务方法添加显式customerRepository.save(customer)
,则也会发生更新。但我的理解是ORM应该自动保存修改过的持久实体。
我确定该问题与Web请求中的EntityManager生命周期有关,但我很困惑。我是否需要进行其他配置?
https://github.com/monztech/SO-41515160
的完整示例 编辑:这已经解决,见下文。根据Spring规范@Transactional
在package-private方法中不起作用,并且错误地没有使更新服务方法公开。
如果方法为public
并且服务类具有@Transactional
注释,则会进行更新。
@Transactional
注释? (没有它就不会发生更新)由于Spring使用的视图机制中的开放会话,独立于任何事务,实体管理器是否仍然不能持久保存对象?
答案 0 :(得分:3)
将您的updateCustomerName
方法设为公开。