配置Spring事务或EJB CMT代替

3

我尝试使用Hibernate配置Spring Boot:

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.datalis.plugin.database.dao.TerminalsService;
import org.datalis.plugin.database.models.TerminalsModel;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Qualifier("terminalsService")
public class TerminalsDaoHibernate implements TerminalsService {

    @Autowired
    private EntityManager entityManager;

    @Override
    @Transactional
    public TerminalsModel getTerminalToken(String terminalToken) throws Exception {
        TerminalsModel terminal = null;
        Session session = entityManager.unwrap(Session.class);
        try {

            entityManager.getTransaction().begin();
            terminal = (TerminalsModel) session.get(TerminalsModel.class, terminalToken);
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
            throw new Exception("Error");
        }
        return terminal;
    }
}

但是我遇到了这个错误:
14:47:34,323 ERROR [stderr] (default task-1) java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
14:47:34,323 ERROR [stderr] (default task-1)    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:255)

如何正确配置@Transactional注解?我需要以不同的方式使用事务吗?


您正在尝试启动另一个事务。不要执行 entityManager.getTransaction().begin(); 等操作。这正是 @Transactional 已经为您做的。 - M. Deinum
你能展示一下我如何在Hibernate中使用EntityManager吗? - Peter Penzov
你已经在做它了,问题是你试图启动另一个事务。你正在与 @Transactional 对抗(正如其名称所示,它处理您的事务)。在您的方法中,您只需要两行代码:1. 从 EntityManager 获取 Session,2. 返回并从 Session 获取值。(尽管我不明白为什么需要这个 Session)。 - M. Deinum
你能否将官方答案和示例代码粘贴在这里,以便我可以给它点赞呢? - Peter Penzov
1个回答

5

您正在使用@Transactional,但仍然尝试手动启动事务。要么进行手动事务管理(即删除@Transactional),要么通过删除手动事务管理代码来采用@Transactional

@Override
@Transactional
public TerminalsModel getTerminalToken(String terminalToken) throws Exception {
    TerminalsModel terminal = null;
    Session session = entityManager.unwrap(Session.class);
    return (TerminalsModel) session.get(TerminalsModel.class, terminalToken);
}

然而我不明白为什么你要在这里使用纯Hibernate而不是JPA。使用JPA可以达到同样的效果。

@Override
@Transactional
public TerminalsModel getTerminalToken(String terminalToken) throws Exception {
    return entityManager.find(TerminalsModel.class, terminalToken);
}

目前的JPA API已经很成熟,因此通常不需要使用纯Hibernate API而是选择JPA。


我可以问一下,如果要通过用户名和密码选择表行,我该如何更新代码?(两个WHERE参数) - Peter Penzov
不要混淆问题(你的问题是关于事务处理的),请仅回答程序相关的内容。 - M. Deinum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接