Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring @事务和JPA对象参数_Spring_Jpa_Transactions - Fatal编程技术网

Spring @事务和JPA对象参数

Spring @事务和JPA对象参数,spring,jpa,transactions,Spring,Jpa,Transactions,在编写多层应用程序时,最好只将对象ID传递给事务性服务方法。但我更愿意传递实际的JPA对象。与此问题不同,一些同事担心a)对象可能属于另一个/无事务,如果在服务方法内部修改会导致问题,b)对象在从UI组件调用此类服务方法后修改会导致问题,因为事务已经提交 用我更喜欢的代码表示 @Named public class MyServiceImpl { ... @Transactional public BigDecimal calculate(ObjectOne objectOn

在编写多层应用程序时,最好只将对象ID传递给事务性服务方法。但我更愿意传递实际的JPA对象。与此问题不同,一些同事担心a)对象可能属于另一个/无事务,如果在服务方法内部修改会导致问题,b)对象在从UI组件调用此类服务方法后修改会导致问题,因为事务已经提交

用我更喜欢的代码表示

@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。更具体地说,,