Hibernate - 交易的样板代码

Posted

技术标签:

【中文标题】Hibernate - 交易的样板代码【英文标题】:Hibernate - Boilerplate code for transactions 【发布时间】:2013-01-12 01:36:23 【问题描述】:

我已经为数据库 CRUD 操作编写了这个服务类。

可见的公共类 CompanyServiceImpl 扩展 PersistentRemoteService 实现 CompanyService

    private GileadHibernateUtil gileadHibernateUtil;

    public CompanyServiceImpl() 
        gileadHibernateUtil = new GileadHibernateUtil();
        setBeanManager(gileadHibernateUtil.getPersistentBeanManager());
    

    @Override
    public void addCompany(Company newCompany) 
        Objects.requireNonNull(newCompany, "newCompany is null.");

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;
        try 
            transaction = session.beginTransaction();
            session.persist(newCompany);
            session.getTransaction().commit();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
            session.close();
        
    

    @Override
    public Company updateCompany(Company company) 
        Objects.requireNonNull(company, "company is null.");

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;
        Company managedCompany = null;

        try 
            transaction = session.beginTransaction();
            managedCompany = (Company) session.merge(company);
            session.getTransaction().commit();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
        

        return managedCompany;
    

    @Override
    public void deleteCompany(Company company) 
        Objects.requireNonNull(company, "company is null.");

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;

        try 
            transaction = session.beginTransaction();
            session.delete(company);
            session.getTransaction().commit();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
        

    

    @Override
    public Company findCompany(int companyId) 
        if (companyId <= 0) 
            throw new IllegalArgumentException("companyId must be a positive integer.");
        

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;
        Company company = null;

        try 
            transaction = session.beginTransaction();
            company = (Company) session.get(Company.class, companyId);
            session.getTransaction().commit();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
        
        return company;
    

    @Override
    public List<Company> findMatchingCompanies(String companyName) 

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;
        List<Company> matchingCompanies = null;

        try 
            transaction = session.beginTransaction();
            Criteria searchCriteria = session.createCriteria(Company.class).add(
                    Restrictions.or(Restrictions.like("code", companyName), Restrictions.like("name", companyName)));
            session.getTransaction().commit();

            matchingCompanies = searchCriteria.list();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
        

        return matchingCompanies;
    

    @Override
    public List<Company> findAllCompanies() 

        Session session = gileadHibernateUtil.getCurrentSession();
        Transaction transaction = null;
        List<Company> companies = null;

        try 
            transaction = session.beginTransaction();
            Criteria searchCriteria = session.createCriteria(Company.class);
            session.getTransaction().commit();

            companies = searchCriteria.list();
         finally 
            if (transaction.isActive()) 
                transaction.rollback();
            
        
        return companies;
    


我决定不使用单独的 DAO 层。它是一个小应用程序,我不会从 Hibernate 切换。它所包含的只是 Hibernate 会话命令。开始和结束事务仍然来自业务层。所以,Hibernate 几乎可以作为我的 DAO 层。 困扰我的是看似样板的交易代码,必须在每个 CRUD 方法中编写。 这是更好的方法,还是无论如何都要重复的最少代码量?

【问题讨论】:

你考虑过使用 Spring 的 Hibernate 支持框架吗? @ToddMurray 目前,它不是一个选项。这是主要问题。 【参考方案1】:

如果您使用的是 spring 并且能够使用注解。提供的链接上有一篇很好的文章,它展示了如何使用注释来包装事务中的方法。

http://springinpractice.com/2008/03/18/annotation-based-transactions-in-spring/

同时使用 spring 和 hibernate 将使您的代码看起来更干净,并且看起来像下面的内容。

@Override
@Transactional
public void addCompany(Company newCompany) 
    Objects.requireNonNull(newCompany, "newCompany is null.");
    Session session = gileadHibernateUtil.getCurrentSession();
    session.persist(newCompany);
    //session.close(); this line would also not be needed because the session would close automatically when the transaction is complete.

【讨论】:

是的。我在几个地方读到 Spring 将帮助清理代码。但是,我现在不应该使用 Spring。那我有什么选择呢? 不确定声明式事务还有哪些其他替代方案。您可能想尝试某种 aop 解决方案。但这也需要另一个库,您可能无法像 AspectJ 那样使用它。 好的。我想我会等一天才能接受这个正确答案。【参考方案2】:

没有弹簧,这样的事情可以使用

java.util.function.Function

 public static Object transactionExecutor(Function<Session, Object> toRun) 
    Session session = null;
    Object result = null;
    try 
        session = getSession();
        final Transaction tx = session.beginTransaction();
        result = toRun.apply(session);
        session.flush();
        tx.commit();
        return result;
     catch (HibernateException he) 
        Transaction tx = session.getTransaction();
        tx.rollback();
     finally 

        session.close();
    
    return result;
 


 public static void save(final Students S) 
    Function<Session, Object> toRun = new Function<Session, Object>() 
        @Override
        public Object apply(final Session t) 
        t.save(S);
        return S.getId();
        
    ;
    int saveID = (int)transactionExecutor(toRun);
 

【讨论】:

以上是关于Hibernate - 交易的样板代码的主要内容,如果未能解决你的问题,请参考以下文章

使用 Hibernate @SQLDelete 对所有实体进行软删除

Hibernate 中的自引用一对一映射

“Spring 事务”和“Hibernate 事务”有啥区别

在Spring和Hibernate中使用TransactionProxyFactoryBean

Spring/Hibernate 应用程序中的角色/权限

Hibernate/JPA - 使用@Future 更新还包含日期字段的实体字段