针对 Hibernate 管理的 POJO 的 Spring AOP 建议

发布于 2024-12-08 06:48:14 字数 2180 浏览 0 评论 0原文

我有一个父子关系,例如订单到订单项目,我在域模型中表示如下:

public class Order {
    private int id;    
    private Set<OrderItem> orderItems = new HashSet<OrderItem>();

    public int getId() {
        return id;
    }

    public void add(OrderItem orderItem) {
        orderItems.add(orderItem);
    }
}

public class OrderItem {
    private int id;

    public int getId() {
        return id;
    }

}

我使用 Hibernate 持久化这些实体,使用如下所示的映射:

<class name="Order" table="ORDERS">
    <id name="id" column="ORDER_ID" access="field">
        <generator class="native" />
    </id>
    <set name="orderItems" table="ORDERS_TO_ITEMS" access="field" cascade="all">
        <key column="ORDER_ID" />
        <many-to-many class="OrderItem" unique="true" column="ITEM_ID" />
    </set>
</class>

<class name="OrderItem" table="ORDER_ITEMS">
    <id name="id" column="ITEM_ID" access="field">
        <generator class="native" />
    </id>
</class>

现在工作得很好。要将订单项添加到订单中(例如在 Spring 控制器方法中),我可以用一种简单明了的方式来完成:

Order order = orderRepository.findById(orderId);
OrderItem item = new OrderItem();
order.add(item);

完成。我什至在 Bean 定义文件中设置了 OpenSessionInViewInterceptor,因此一旦控制器方法完成,订单项就会被持久化。

问题是我想立即调用 item.getId() ,但是当 order.add(item) 方法返回时,事务尚未提交,并返回零。最佳实践似乎是创建一个事务服务方法,我是这样做的:

Order order = orderRepository.findById(orderId);
OrderItem item = new OrderItem();
orderService.addItem(order, item)

现在 item.getId() 立即返回生成的 ID。

我遇到的问题是 orderService.addItem 方法除了将 order.add(item) 方法包装在事务中之外没有其他任何用途。我想知道如何摆脱它。

我的问题是,如何才能使 order.add(item) 方法具有事务性?

我认为唯一的方法是,与 Hibernate 会话交互的 orderRepository 必须返回一个Spring AOP 或 AspectJ 代理,我可以在 Bean 定义文件中将其 add(item) 方法声明为事务性方法。

我怎样才能返回这样一个Spring管理的代理订单?我可以通过重写 Hibernate 的 Interceptor.onLoad 方法来实现吗?

有没有其他方法可以使 Order(具体实现)与 Spring Transaction Advisor 关联?

我知道我实现的服务可能是最实用的解决方案,但我真的很想知道如何将 AOP Advice 附加到 Hibernate 持久 POJO 实体。

I have a parent-child relationship, such as Order to Order Item, which I have represented in the domain model like this:

public class Order {
    private int id;    
    private Set<OrderItem> orderItems = new HashSet<OrderItem>();

    public int getId() {
        return id;
    }

    public void add(OrderItem orderItem) {
        orderItems.add(orderItem);
    }
}

public class OrderItem {
    private int id;

    public int getId() {
        return id;
    }

}

I am persisting these entities with Hibernate, using a mapping like this:

<class name="Order" table="ORDERS">
    <id name="id" column="ORDER_ID" access="field">
        <generator class="native" />
    </id>
    <set name="orderItems" table="ORDERS_TO_ITEMS" access="field" cascade="all">
        <key column="ORDER_ID" />
        <many-to-many class="OrderItem" unique="true" column="ITEM_ID" />
    </set>
</class>

<class name="OrderItem" table="ORDER_ITEMS">
    <id name="id" column="ITEM_ID" access="field">
        <generator class="native" />
    </id>
</class>

This is working very nicely now. To add an Order Item to an Order, for example in a Spring Controller method, I can do it in a simple and clean way:

Order order = orderRepository.findById(orderId);
OrderItem item = new OrderItem();
order.add(item);

Done. I even set-up the OpenSessionInViewInterceptor in my Bean Definition file, so as soon as the controller method completes, the Order Item is persisted.

The issue is I would like to call item.getId() right away, but when the order.add(item) method returns, the transaction has not yet been commited, and zero is returned. The best practice seems to be creating a transactional service method, and I did it like this:

Order order = orderRepository.findById(orderId);
OrderItem item = new OrderItem();
orderService.addItem(order, item)

Now item.getId() returns the generated ID right away.

The issue I have is the orderService.addItem method serves no purpose other than to wrap the order.add(item) method in a transaction. I would like to know how I can get rid of it.

My question is, how can I possibly make the order.add(item) method transactional?

The only way I see it, the orderRepository interacting with the Hibernate session must return a Spring AOP or AspectJ proxy, whose add(item) method I can declare as transactional in my Bean Definition file.

How would I be able to return such a Spring managed proxy Order? Can I do it by overriding Hibernate's Interceptor.onLoad method?

Is there any other way to make the Order, a concrete implementation, be associated with a Spring Transaction Advisor?

I know the service I implemented is probably the most practical solution, but I am really curious to know how I can attach AOP Advice to a Hibernate persisted POJO entity.

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

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

发布评论

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

评论(1

A君 2024-12-15 06:48:14

您正在寻找的是 “使用 AspectJ 通过 Spring 依赖注入域对象”。我有两个 构建时间 的可执行示例和加载时间编织可以在 github 上找到。

What you're looking for is "Using AspectJ to dependency inject domain objects with Spring". I have executable examples of both build-time and load-time weaving available on github.

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