You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hibernate JPA时,如何划分MVC(除视图外)的代码结构与事务?

分层逻辑与JPA组件职责划分建议

核心原则

Service层负责业务逻辑编排+事务边界控制,Repository层只负责纯数据CRUD操作,这是分层架构的核心准则,以此为基础来分配JPA组件的职责:


各JPA组件的放置方案

1. EntityManagerFactory(emf)

  • emf是重量级对象,创建和销毁成本极高,绝对不能在Service/Repository的方法内重复创建。
  • 正确做法:在应用启动时初始化一次,作为全局单例复用(比如放在静态代码块、Spring的配置类中),避免每次业务调用都重新创建。

2. EntityManager(em)

  • em是轻量级对象,生命周期与事务绑定,必须由Service层管理。
  • 原因:Repository的操作必须在Service的事务范围内执行,否则无法保证数据一致性。Service层创建em后,通过构造函数或方法参数传递给RepositoryImpl使用,Repository只负责用em执行CRUD,不管理其生命周期。

3. EntityTransaction(tx)

  • 事务控制完全属于Service层职责,因为一个业务方法可能涉及多个Repository操作(比如先查再改),需要统一的事务边界(要么全成功,要么全回滚)。
  • tx的开启、提交、回滚逻辑必须放在Service层,Repository层不碰任何事务相关代码。

代码调整示例

Service层代码(事务+em管理)

// 全局单例emf,应用启动时初始化一次
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

public UserInfo handleLogin(String id, String pw) {
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    UserInfo result = null;
    try {
        tx.begin();
        // 将当前em传入Repository
        LoginRepository repo = new LoginRepositoryImpl(em);
        List<UserInfo> users = repo.findUser(id, pw);
        
        // 这里处理业务逻辑:比如判断用户是否存在、生成登录凭证等
        result = users.isEmpty() ? null : users.get(0);
        
        tx.commit();
    } catch (Exception e) {
        if (tx.isActive()) {
            tx.rollback();
        }
        throw new RuntimeException("登录失败", e);
    } finally {
        em.close();
    }
    return result;
}

RepositoryImpl代码(纯数据操作)

public class LoginRepositoryImpl implements LoginRepository{
    private final EntityManager em;

    // 通过构造函数注入Service层传递的em
    public LoginRepositoryImpl(EntityManager em) {
        this.em = em;
    }

    @Override
    public List<UserInfo> findUser(String id, String pw) {
        // 使用em执行JPQL查询,只做纯数据操作
        String jpql = "SELECT u FROM UserInfo u WHERE u.id = :id AND u.pw = :pw";
        return em.createQuery(jpql, UserInfo.class)
                .setParameter("id", id)
                .setParameter("pw", pw)
                .getResultList();
    }
}

最佳实践(结合Spring)

如果使用Spring框架,完全可以摆脱手动管理的繁琐:

  • Service层用@Transactional注解自动控制事务,无需手动操作tx;
  • Repository层用@Repository注解,通过@PersistenceContext自动注入与当前事务绑定的em;
  • emf由Spring容器自动管理,无需手动创建。

示例代码:

// Service层
@Service
public class LoginService {
    private final LoginRepository loginRepository;

    // 构造注入Repository
    public LoginService(LoginRepository loginRepository) {
        this.loginRepository = loginRepository;
    }

    @Transactional
    public UserInfo login(String id, String pw) {
        List<UserInfo> users = loginRepository.findUser(id, pw);
        // 业务逻辑处理
        return users.isEmpty() ? null : users.get(0);
    }
}

// RepositoryImpl层
@Repository
public class LoginRepositoryImpl implements LoginRepository{
    @PersistenceContext
    private EntityManager em;

    @Override
    public List<UserInfo> findUser(String id, String pw) {
        String jpql = "SELECT u FROM UserInfo u WHERE u.id = :id AND u.pw = :pw";
        return em.createQuery(jpql, UserInfo.class)
                .setParameter("id", id)
                .setParameter("pw", pw)
                .getResultList();
    }
}

内容的提问来源于stack exchange,提问作者JayCold

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 03:06:38