Spring Boot JPA @Transactional @Service不会更新,但控制器中的@Transactional会更新

时间:2017-01-06 22:09:51

标签: spring hibernate spring-boot spring-data-jpa

我有一个非常基本的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使用的视图机制中的开放会话,独立于任何事务,实体管理器是否仍然不能持久保存对象?

1 个答案:

答案 0 :(得分:3)

将您的updateCustomerName方法设为公开。