I had a controller method that updates some fields of an order entity. I traced the execution flow of the controller method in debug mode. And I found that the transaction commits too early. The transaction commits just after call repository update method. what's the problem?
source codes are below.
// Controller
@RestController
@RequestMapping(value = "/test", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public class TxTestController extends BaseController {
@Autowired
private OrderRepository orderRepository;
@Transactional
@GetMapping(value = "/update")
public void updateOrder() throws Exception {
Order order = orderRepository.findAll().get(0);
order.setFeeRemains(order.getFeeRemains().add(BigDecimal.valueOf(100000000)));
orderRepository.updateOrder(order.getId(), order.getRemains(), order.getFeeRemains(), order.getStatus());
// The transaction is commited after execution of the above line.
// and the external database tools can see the changed data from here.
// So no way to rollback transaction after this line.
System.out.println(order);
// do another persistence jobs
}
}
// Repository
public interface OrderRepository extends JpaRepository<Order, String>, QueryDslPredicateExecutor<Order> {
@Modifying
@Query("update Order o set o.remains = :remains, o.feeRemains = :feeRemains, o.status = :status where o.id = :orderId")
void updateOrder(@Param("orderId") String orderId,
@Param("remains") BigDecimal remains,
@Param("feeRemains") BigDecimal feeRemains,
@Param("status") Order.Status status);
}
// application.yml
spring:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
generate-ddl: true
hibernate:
ddl-auto: update
show-sql: false
datasource:
url: jdbc:mysql://localhost:3306/plutusds
username: root
password: root
testWhileIdle: true
validationQuery: SELECT 1
// pom dependencies
<?xml version="1.0" encoding="UTF-8"?>
...
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
</dependency>
...
</dependencies>
...
</project>
if I remove the @Transactional
annotation from the controller method, then
javax.persistence.TransactionRequiredException occurred.