我有一个控制器方法,它更新订单实体的某些字段。我在调试模式下跟踪了控制器方法的执行流程。我发现事务提交过早。事务在调用存储库更新方法后立即提交。这是什么问题?
源代码在下面。
//控制器
@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依赖
<?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>
型
如果我从控制器方法中删除@Transactional
注解,则会发生javax.persistence. TransactionAddressedException。
3条答案
按热度按时间mtb9vblg1#
在spring中,
@Transactional
定义了单个数据库事务。由于spring内部使用HibernateEntityManager
来管理数据库事务的会话,并且是自动处理的。一旦数据库事务成功,就会进行提交。我们可以在一个方法中有多个数据库事务。在这种情况下,commit
将在每个成功的事务后发生。@Transactional
并不意味着我们使用的方法。它只是说该方法有一个数据库事务,并且将由spring处理。另一点是我们不应该在控制器上写transactional级别,我们应该为它提供一个服务类,在那里我们可以使用transactional。请参阅下面的链接,其中详细介绍了
@Transactional
。How Spring Jpa Transactional Works
iklwldmw2#
很长很长一段时间以来,我们都无法使用默认的Java代理机制在控制器上使用@ translation annotations。Spring创建了一个控制器的代理,管理transactions的annotation processor失去了
@Transactional
annotation的可见性,因为它只能看到代理。TL;DR:Spring托管的transactions无法在controller中启动,请将其移到服务层。
顺便说一下,控制器不应该有业务逻辑,因为你有(这3行'查找-设置-更新'是业务逻辑)。
ggazkfy83#
这个问题是由于mysql引擎类型。
默认情况下,Hibernate使用MyISAM引擎创建表,而MyISAM引擎不是事务性的。基本上,您只需要定义Hibernate的方言即可切换到InnoDB等事务性引擎类型。
试试这个:
字符串
下面的链接包含了关于mysql引擎类型的有用细节作为摘要信息:
https://www.w3resource.com/mysql/mysql-storage-engines.php