[英]How can I integrate Spring transaction management with Hibernate?
我一直在嘗試使用 HibernateTransactionManager 來管理我的服務層中的事務,但它不起作用。 Java class 用於創建 PlatformTransactionManager 的配置:
@Configuration
@EnableTransactionManagement
@PropertySource("classpath:hibernateConfig.properties")
public class HibernateConfig {
@Value("${hibernate.dialect}")
private String dialect;
//Other hibernate properties
@Autowired
private DataSource dataSource;
private Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", dialect);
//Other hibernate properties removed here for brevity
return hibernateProperties;
}
@Bean
@DependsOn("dataSource")
public SessionFactory sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean =
new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setPackagesToScan("com.ldp.vigilantBean.domain");
sessionFactoryBean.setHibernateProperties(hibernateProperties());
sessionFactoryBean.afterPropertiesSet();
return sessionFactoryBean.getObject();
}
@Bean
@DependsOn("sessionFactory")
public PlatformTransactionManager platformTransactionManager() throws IOException {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory());
txManager.afterPropertiesSet();
return txManager;
}
}
在這個方法調用的后面,有兩次對持久層的調用,最后拋出了一個運行時異常。 所以我希望回滾這兩個對存儲庫的調用。
@Override
@Transactional(rollbackFor = { RuntimeException.class })
public boolean removeCartItem(Long cartItemId) {
Cart cart = getCartOutOfContext();
Optional<CartItem> optCartItemToRemove =
cart.getCartItems()
.stream()
.filter(cartItem -> cartItem.getCartItemId().equals(cartItemId))
.findAny();
if (optCartItemToRemove.isPresent()) {
CartItem cartItemToRemove = optCartItemToRemove.get();
//There is a bug with PersistentSet in Hibernate that makes
//using .contains() and .remove() methods of Set interface unpredictable.
//This is a workaround: reset the whole set.
cart.setCartItems(
cart.getCartItems().stream()
.filter(cartItem -> !cartItem.equals(cartItemToRemove))
.collect(Collectors.toSet())
);
Optional<Product> optProduct =
productRetrievalRepository.getProductById(cartItemToRemove.getProduct().getProductId());
if (!optProduct.isPresent())
throw new IllegalArgumentException("Specified product not found");
Product productToRemove = optProduct.get();
productToRemove.setUnitsInOrder(productToRemove.getUnitsInOrder() - cartItemToRemove.getQuantity());
//First call
productAlterRepository.updateProduct(productToRemove);
//Second call
cartRepository.updateCart(cart);
if (true) throw new RuntimeException("An exception to check transactions");
return true;
} else
return false;
}
用於管理產品的存儲庫:
@Repository
class ProductAlterRepositoryImpl implements ProductAlterRepository {
private SessionFactory sessionFactory;
public ProductAlterRepositoryImpl(
@Autowired
SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public Optional<Product> updateProduct(Product product) {
try (Session session = sessionFactory.openSession()) {
session.getTransaction().begin();
session.merge(product);
session.getTransaction().commit();
}
return Optional.of(product);
}
}
我不明白為什么在我的服務方法中拋出 RuntimException 之前所做的更改沒有回滾:我使用相同的 session 工廠來初始化平台事務管理器並通過我的存儲庫中的 Session 進行更改。 另外,我的記錄器中有這條線
*** LOG4J *** HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
如果我是對的,當只使用一個資源(在我的例子中是 Hibernate 存儲庫)時,您不需要像 Atomikos 這樣的全局事務提供程序。 我認為假設有 3 個事務:一個外部(服務調用)和 2 個內部(存儲庫)。 這個想法是,如果內部事務之一失敗,它應該導致外部事務回滾,這意味着對存儲庫的所有兩個調用都將被回滾。
在 updateProduct(Product) 內部,除了服務級別的聲明之外,您還再次打開了程序化事務。 因此它將忽略 Spring 容器管理的事務管理器,並將單獨使用它自己的。 能否請您刪除並重試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.