Spring @事务和JPA对象参数
在编写多层应用程序时,最好只将对象ID传递给事务性服务方法。但我更愿意传递实际的JPA对象。与此问题不同,一些同事担心a)对象可能属于另一个/无事务,如果在服务方法内部修改会导致问题,b)对象在从UI组件调用此类服务方法后修改会导致问题,因为事务已经提交 用我更喜欢的代码表示Spring @事务和JPA对象参数,spring,jpa,transactions,Spring,Jpa,Transactions,在编写多层应用程序时,最好只将对象ID传递给事务性服务方法。但我更愿意传递实际的JPA对象。与此问题不同,一些同事担心a)对象可能属于另一个/无事务,如果在服务方法内部修改会导致问题,b)对象在从UI组件调用此类服务方法后修改会导致问题,因为事务已经提交 用我更喜欢的代码表示 @Named public class MyServiceImpl { ... @Transactional public BigDecimal calculate(ObjectOne objectOn
@Named public class MyServiceImpl
{
...
@Transactional
public BigDecimal calculate(ObjectOne objectOne, ObjectTwo objectTwo)
{
...
}
}
而不是
@Named public class MyServiceImpl
{
...
@Transactional
public BigDecimal calculate(long objectOneId, long objectTwoId)
{
ObjectOne objectOne = objectOneService.find(objectOneId);
ObjectTwo objectTwo = objectTwoService.find(objectTwoId);
...
}
}
那么,有没有一种技术可以让事务管理器(spring)正确地处理对象呢?或者,您是否建议显式地使用JPA merge或其他方法来正确处理直接对象引用?或者您是否也不鼓励传递对象而不是ID
特别是带有官方或知名来源链接的解释显然会有所帮助。根据我的经验,我更喜欢传递对象而不是ID。根据您的示例,这是一个非常简单的场景。但在实时中,对象可能非常复杂,并且有许多子对象。在这种情况下,每次检索对象都会影响性能 它根据场景而变化。对于复杂对象,我更愿意将对象存储在会话中,并将其传递给实体管理器,然后将其合并到实体管理器中
此外,它还取决于其他因素,如您希望在会话中保留多少数据(在传递完整对象的情况下),或者您每次检索对象时可以承受多少性能下降。您对分离对象的概念尚不清楚。有关JPA/hibernate中的不同对象状态及其发生时间,请参阅下面的链接
例如,根据我的经验,正确的方法在中间:根据您的用例(即业务逻辑),您将需要一个或另一个 使用ID的示例: 假设信用审批人希望批准或拒绝信用。为此,我肯定会选择ID: ApprovalService.approveCreditRequest(长creditRequestId,ApprovalStatus ApprovalStatus); 在web层中获取
CreditRequest
的问题对我来说似乎是一个无用的调用,假设这不是问题,您必须确保在EJB/服务层中,web层向您发送正确加载的CreditRequest
实例,即web层中没有人更改任何重要字段,类似于creditRequest.setApprovalStatus(ApprovalStatus.DENY)
或creditRequest.setRequester(另一个请求者)
。而且也不要只考虑WebLayer,因为可能有一个远程Ejb调用您的服务层,您必须信任它。另一个您确实希望使用IDs的用例是在以下场景中:您有一个批处理,通过调用方法approveCreditRequest()
,批准了许多(成千上万)个creditrequest
。从数据库中获取所有实体及其所有关系(而不仅仅是它们的ID)肯定是一个性能瓶颈,将每个实例传递给该方法可能会批准某些CreditRequests两次(例如,在获取实例和调用approveCreditRequest()
的同时,它已经被批准)
这种方法的缺点是:不容易进行UnitTest
,您将需要集成测试或模拟框架(例如)
使用完整对象的示例:
假设您需要在HTTP请求后更改90%的字段,例如,在更新实体时。比处理整个对象更容易
现在与实例的托管状态相关:当实体实例离开服务层(无论是EJB还是Springbeans)时,您必须确保事务已关闭(在WebLayer中,永远不要使用事务),因此实体将自动取消管理,这样,您就可以在WebLayer中毫无问题地更改它们。按原样,将业务对象传递到事务方法中应该没问题。如果调用操作已经打开了一个事务,则会打开一个新的虚拟事务(对于相同的物理事务),并且对象引用保持不变。如果没有事务处于活动状态,则不会损害持久状态
要确保对象是正常的,您可以执行以下操作
@Transactional
public BigDecimal calculate(ObjectOne objectOne, ObjectTwo objectTwo)
{
objectOne = objectOneService.find(objectOne.getId());
objectTwo = objectTwoService.find(objectTwo.getId());
...
}
这很便宜,因为对象是从缓存中获取的。但这不是必需的,因为对象位于同一物理事务中
如果对象确实来自不同的事务,则可以使用上面的代码来解决它。但您的调用方法将不会看到对对象所做的任何更改,除非它再次从数据库中获取其对象(并根据隔离情况启动新事务)。是的,这正是我所指的分离对象的概念。您认为什么是不清楚的?根据您的陈述-a)对象可能在服务方法内部分离,b)对象可能在从UI组件调用此类服务方法后分离/断开。我想这还不清楚。对象将在会话关闭后分离,让它处于服务或任何其他层中。现在,若您想将分离的对象传递到UI中,那个么不鼓励这样做,您应该创建新的客户机模型,并在将dao模型传递到UI时将其复制到客户机模型中。从UI中,您将获得客户机模型,将其复制到dao模型,然后将其合并。我试图改善我问题中的顾虑。但实际的问题是,通过物体被认为是一种好的做法还是坏的做法。您可以传递对象,最佳实践是创建另一个模型类,并将DAO/DTO复制到该模型类实例的对象状态,以将其传递到UI或任何其他层。不要将DAO/DTO对象传递给UI。更具体地说,,