在 Spring/Hibernate 中删除或更新之前验证对象是否存在
我在我的项目中使用 Spring/Hibernate 组合,并具有标准的 CRUD 操作。
我想知道,在删除或更新对象之前验证对象存在是否合理?如果是,最合适的地方在哪里——service层还是dao层?
编辑:
抱歉,我一开始问这个问题的时候没有说出重点。存在检查的唯一动机是向服务客户端抛出友好异常(不特定于 DAO)。
问题是我“必须”进行存在性检查,因为下面的服务方法是事务性的,除此之外,我还使用 HibernateTemplate 和 DaoSupport 帮助程序类在 DAO 对象中进行会话操作。
根据提到的,Hibernate 异常(例如在删除不存在的实例的情况下)在提交时抛出,这是我无法达到的,因为(我想)提交是由代理对象中的 PlatformTransactionManager 执行的,我没有机会在我的服务方法中处理该异常并向客户端重新抛出一些友好的异常。
但即使我保留在删除之前检查存在性的策略,不好的事情是,在实例存在的情况下,我会遇到 NonUniqueObjectException 问题,因为我重新附加(在删除时)已加载的实例(在读取时由于存在)检查)。
例如:
//Existence checking in this example is not so important
public void delete(Employee emp){
Employee tempEmp=employeeDao.read(emp.getId());
if(tempEmp==null)
throw new SomeAppSpecificException();
}
//Existence checking in this example is maybe 'more logical'
public void save(Assignment a){
Task t=taskDao.read(a.getTask().getId());
if(t==null)
throw new FriendlyForeignKeyConstraintException();
Employee e=employeeDao.read(a.getEmployee().getId());
if(e==null)
throw new EmployeeNotFoundExc();
//...some more integrity checking and similar...
assignmentDao.save(a);
}
重点是,我只想在提到的情况(完整性违规等)的情况下抛出带有适当消息的友好异常。
I'm using Spring/Hibernate combination for my project, with standard CRUD operations.
I wonder, is it reasonable to validate object existence before its deletion or update? If it is, where is the most appropriate place to do - service or dao layer?
EDIT:
Sorry, I didn't make the point at first when I asked this question. The only motive for existence checking is to throw friendly exception to client of service (no DAO specific).
Problem is that I 'have to do' existence checking because my service method below is transactional, and besides that, I'm using HibernateTemplate and DaoSupport helper classes for session manipulation in DAO objects.
According to mentioned, Hibernate exception (in case of deleting non-existing instance for example) is thrown at commit time, which is out of my reach, because (I suppose) commit is executed by PlatformTransactionManager in proxy object, and I have no opportunity to handle that exception in my service method and re-throw some friendly exception to the client.
But even if I keep my strategy to check existence before deletion, bad stuff is that I have problems with NonUniqueObjectException in the case that instance exist, because I re-attach (in delete-time) already loaded instance (in read-time due existence checking).
For example:
//Existence checking in this example is not so important
public void delete(Employee emp){
Employee tempEmp=employeeDao.read(emp.getId());
if(tempEmp==null)
throw new SomeAppSpecificException();
}
//Existence checking in this example is maybe 'more logical'
public void save(Assignment a){
Task t=taskDao.read(a.getTask().getId());
if(t==null)
throw new FriendlyForeignKeyConstraintException();
Employee e=employeeDao.read(a.getEmployee().getId());
if(e==null)
throw new EmployeeNotFoundExc();
//...some more integrity checking and similar...
assignmentDao.save(a);
}
The point is that I just want to throw friendly exception with appropriate message in the case of mentioned situations (integrity violations and similar).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 Hibernate 术语中,更新和删除操作(以及 Session)处理持久化实体。因此,它们的存在是隐含的,并且在代码中再次验证它是毫无意义的 - Hibernate 会自行执行此操作,如果情况并非如此,则会抛出异常。然后您可以捕获并处理(或重新抛出)该异常。
附带说明(基于您的示例代码),无需显式读取您要删除的实例。会话提供load() 方法将返回适合传递给
delete()
方法的代理实例,而无需实际访问数据库。它假定与给定 PK 关联的实例存在,如果情况不存在,稍后将会失败(抛出异常)。编辑(基于问题澄清):
当您说要向客户端抛出“友好”异常时,“友好”和“客户端”的定义变得很重要。在大多数现实场景中,您的事务将不仅仅跨越您的服务之一上的简单原子“save()”或“delete()”方法。
如果客户端是本地的,并且您不需要在单个客户端交互中进行单独的事务(典型场景 - Web 应用程序在具有服务层的同一 VM 中运行),那么通常最好在那里启动/提交事务(请参阅 在视图中打开会话)。然后,您可以在提交期间捕获并正确处理(包括包装/重新抛出,如果需要)异常。其他场景更复杂,但最终异常将传播到您的“顶级”客户端;只是如果您需要以“友好”的方式向客户展示“根本”原因,那么打开它可能会很复杂。
但最重要的是,这取决于您。如果您宁愿因自己的异常而快速失败(以编写一些样板代码为代价),那么这并没有什么问题。
In Hibernate terms, both update and delete operations (and corresponding methods on Session) deal with persisted entities. Their existence is, therefore, implied and verifying it again in your code is kind of pointless - Hibernate will do that on its own and throw an exception if that's not the case. You can then catch and handle (or rethrow) that exception.
On a side note (based on your sample code), it's not necessary to explicitly read the instance you're going to delete. Session provides load() method that will return proxy instance suitable for passing to
delete()
method without actually hitting the database. It assumes that instance associated with given PK exists and will fail (throw an exception) later if that's not the case.Edit (based on question clarification):
When you say you want to throw "friendly" exception to the client, the definitions of "friendly" and "client" become important. In most real-life scenarios your transaction would span across more than a simple atomic "save()" or "delete()" method on one of your services.
If the client is local and you don't need separate transactions within a single client interaction (typical scenario - web app running in the same VM with service layer), it's usually a good idea to initiate / commit transaction there (see Open Session In View, for example). You can then catch and properly handle (including wrapping / re-throwing, if needed) exceptions during commit. Other scenarios are more complicated, but ultimately the exception will be propagated to your "top level" client; it's just that unwrapping it may prove to be complicated if you need to present the "root" cause to the client in a "friendly" way.
The bottom line, though, is that it's up to you. If you'd rather fail fast with your own exception (at the expense of writing some boilerplate code), there's nothing really wrong with that.