带有事务的 Hibernate 模板

发布于 2024-12-09 14:23:50 字数 388 浏览 0 评论 0原文

我有一个使用 HibernateTemplate 的 java/spring web 应用程序,我想知道是否可以将 SQL 事务与 hibernate 模板一起使用。

例如,假设我有以下 dao 代码:

getHibernateTemplate().save(newObject);
getHibernateTemplate().saveOrUpdate(someObject);
getHibernateTemplate().delete(oldObject);

假设我希望所有三个语句都成功或所有三个语句都失败。有什么方法可以使用休眠模板来完成此任务吗?我可以使用 try/catch 块吗?如果是这样,我会在 catch 块中放入什么来回滚 hibernate 模板语句?

I have a java/spring webapp which uses HibernateTemplate and I was wondering if it was possible to use SQL transactions with hibernate template.

For example, suppose that I have the following dao code:

getHibernateTemplate().save(newObject);
getHibernateTemplate().saveOrUpdate(someObject);
getHibernateTemplate().delete(oldObject);

Suppose that I want either all three statements to succeed or all three to fail. Is there any way to accomplish this with hibernate template? Can I use a try/catch block? If so, what would I put in the catch block to rollback the hibernate template statements?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我只土不豪 2024-12-16 14:23:50

正如 @hvgotcodes 指出的,事务是在服务层而不是持久层中管理的。这是由于事务性的含义=>大多数时候是由业务定义的,因此是服务/域层。

下面是如何通过 Spring AOP XML 配置处理服务的示例:

<aop:config>
    <aop:pointcut id="moneyMakingBusinessServiceMethods"
                  expression="execution(* org.gitpod.startup.service.MoneyMakingBusinessService.*(..))"/>

    <aop:advisor advice-ref="moneyMakingAdvice"
                 pointcut-ref="moneyMakingBusinessServiceMethods"/>
</aop:config>

<tx:advice id="moneyMakingAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="makeMoney" propagation="REQUIRED"/>
        <tx:method name="withdrawMoney" propagation="REQUIRED" read-only="true"/>            
        <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
</tx:advice>

这种方法很好,因为您不需要使用 @Transactional@SomethingElse 来污染您的服务注释,并且所有 TX 管理/配置都在一个地方定义 [这是我个人的信念]。

该服务将采用一两个 Dao/Repository,并将所有持久性工作委托给它:

public class CleverMoneyMakingBusinessService implements MoneyMakingBusinessService {

    private MoneyRepository moneyRepository;

    public void makeMoney( MoneyRoll money )  {
        moneyRepository.make( money );
    }

    public MoneyRoll withdrawMoney( Long moneyRollId ) {
        return moneyRepository.find( moneyRollId );
    }

    public void setMoneyRepository( MoneyRepository moneyRepository ) {
        this.moneyRepository = moneyRepository;
    }
}

而 Repository/DAO 可能如下所示(请注意,它不使用 HibernateTemplate,因为 @ Repository 完成所有异常转换,Hibernate SessionFactory 可以并且应该直接使用):

@Repository
public class HibernateMoneyRepository implements MoneyRepository {

    private SessionFactory sessionFactory;

    public MoneyRoll find( Long rollId ) {

        MoneyRoll moneyRoll = null;

        Query query = getSession().getNamedQuery("find.moneyroll.by.id");
        query.setParameter( "id", rollId );

        List<MoneyRoll> moneyList = query.list();

        if ( moneyList.size() != 0 ) {
            moneyRoll = ( MoneyRoll )query.list().get( 0 );
        }

        return moneyRoll;
    }

    public void make( MoneyRoll moneyRoll ) {
        getSession().save( moneyRoll );
    }

    public void takeOut( MoneyRoll moneyRoll ) {
        getSession().delete( moneyRoll );
    }

    public void update(MoneyRoll money) {

        Query query = getSession().getNamedQuery("update.moneyroll");
        query.setParameter( "id", money.getId() );
        query.setParameter( "amount", money.getAmount() );
        query.setParameter( "currency", money.getCurrency() );

        query.executeUpdate();
    }

    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }   
}

看一下 赚钱项目,我将其放在一起作为示例,看看它是如何组合在一起并执行的。

As @hvgotcodes pointed out, transactions are managed on the Service layer rather than in a persistence layer. This is due to the meaning of things to be transactional => which most of the time is defined by the business, hence service/domain layer.

Here is an example of how to transact your service via Spring AOP XML configuration:

<aop:config>
    <aop:pointcut id="moneyMakingBusinessServiceMethods"
                  expression="execution(* org.gitpod.startup.service.MoneyMakingBusinessService.*(..))"/>

    <aop:advisor advice-ref="moneyMakingAdvice"
                 pointcut-ref="moneyMakingBusinessServiceMethods"/>
</aop:config>

<tx:advice id="moneyMakingAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="makeMoney" propagation="REQUIRED"/>
        <tx:method name="withdrawMoney" propagation="REQUIRED" read-only="true"/>            
        <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
</tx:advice>

This approach is good, because you do not need to pollute your services with @Transactional, @SomethingElse annotations, and all your TX management/configuration is defined in a single place [ this is my personal belief ].

This service will take a Dao/Repository or two, and will delegate all the persistence workings to it:

public class CleverMoneyMakingBusinessService implements MoneyMakingBusinessService {

    private MoneyRepository moneyRepository;

    public void makeMoney( MoneyRoll money )  {
        moneyRepository.make( money );
    }

    public MoneyRoll withdrawMoney( Long moneyRollId ) {
        return moneyRepository.find( moneyRollId );
    }

    public void setMoneyRepository( MoneyRepository moneyRepository ) {
        this.moneyRepository = moneyRepository;
    }
}

Whereas Repository/DAO may look like this (note that it does not use HibernateTemplate, since @Repository does all the Exception translations, and Hibernate SessionFactory can and should be used directly):

@Repository
public class HibernateMoneyRepository implements MoneyRepository {

    private SessionFactory sessionFactory;

    public MoneyRoll find( Long rollId ) {

        MoneyRoll moneyRoll = null;

        Query query = getSession().getNamedQuery("find.moneyroll.by.id");
        query.setParameter( "id", rollId );

        List<MoneyRoll> moneyList = query.list();

        if ( moneyList.size() != 0 ) {
            moneyRoll = ( MoneyRoll )query.list().get( 0 );
        }

        return moneyRoll;
    }

    public void make( MoneyRoll moneyRoll ) {
        getSession().save( moneyRoll );
    }

    public void takeOut( MoneyRoll moneyRoll ) {
        getSession().delete( moneyRoll );
    }

    public void update(MoneyRoll money) {

        Query query = getSession().getNamedQuery("update.moneyroll");
        query.setParameter( "id", money.getId() );
        query.setParameter( "amount", money.getAmount() );
        query.setParameter( "currency", money.getCurrency() );

        query.executeUpdate();
    }

    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }   
}

Take a look at the money making project that I put together as an example, to see how it all comes together and executes.

半岛未凉 2024-12-16 14:23:50

使用 Spring 来管理您的事务(我将其视为您的标签之一)。

基本思想是将一堆持久性操作分组,您希望所有操作都参与一个事务、一个方法(在服务类中),并且您 配置 Spring 以使该服务方法具有事务性。

一种相对简单的方法是配置 spring 使所有服务方法都具有事务性,但您并不局限于此——您可以根据需要使其变得简单或复杂。

Use Spring to manage your transactions (I see it as one of your tags).

The basic idea is that you group a bunch of persistence operations, that you want to all participate in one transaction, in one method (in a service class), and you configure Spring to make that service method transactional.

One relatively easy way to do it is to configure spring to make all service methods transactional, but you are not constrained to this -- you can make it as easy or complicated as you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文