Seb*_*ber 15 java orm hibernate jpa java-ee
如何用Hibernate/ORM(或其他ORM ......)保持干净的层?
清洁层分离的意思是将所有Hibernate内容保存在DAO层中.
例如,在创建一个大的CSV导出流时,我们应该经常做一些像evict这样的Hibernate操作来避免OutOfMemory ...输出流的填充属于视图,但是evict属于DAO.
我的意思是我们不应该将evict操作放在前端/服务中,我们也不应该把业务逻辑放在DAO中......那么在这种情况下我们能做些什么呢?
在许多情况下,你必须做一些事情,如逐出,刷新,清除,刷新,特别是当你玩交易,大数据或类似的事情...
那么你如何使用像Hibernate这样的ORM工具来保持清晰的层分离?
编辑:在工作中我不喜欢的是我们有一个自定义抽象DAO,允许服务将Hibernate标准作为参数.这是实用的,但对我来说理论上称这个DAO的服务不应该知道一个标准.我的意思是,我们不应该以任何方式将Hibernate内容导入业务/视图逻辑.
有答案,简单还是其他?
如果"干净"是指上层不了解较低层的实现,通常可以应用 Tell,不要求原则.对于您的CSV流媒体示例,它会是这样的,例如:
// This is a "global" API (meaning it is visible to all layers). This is ok as
// it is a specification and not an implementation.
public interface FooWriter {
void write(Foo foo);
}
// DAO layer
public class FooDaoImpl {
...
public void streamBigQueryTo(FooWriter fooWriter, ...) {
...
for (Foo foo: executeQueryThatReturnsLotsOfFoos(...)) {
fooWriter.write(foo);
evict(foo);
}
}
...
}
// UI layer
public class FooUI {
...
public void dumpCsv(...) {
...
fooBusiness.streamBigQueryTo(new CsvFooWriter(request.getOutputStream()), ...);
...
}
}
// Business layer
public class FooBusinessImpl {
...
public void streamBigQueryTo(FooWriter fooWriter, ...) {
...
if (user.canQueryFoos()) {
beginTransaction();
fooDao.streamBigQueryTo(fooWriter, ...);
auditAccess(...);
endTransaction();
}
...
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以自由地处理您的特定ORM.这种"回调"方法的缺点是:如果你的层在不同的JVM上,那么它可能不是很可行(在这个例子中,你需要能够序列化CsvFooWriter).
关于通用DAO:我从未感到需要,我发现的大多数对象访问模式都不同,足以使特定的实现成为可取的.但是,确实进行层分离并强制业务层创建Hibernate标准是相互矛盾的路径.我会在DAO层为每个不同的查询指定一个不同的查询方法,然后我会让DAO实现以它可能选择的任何方式获得结果(条件,查询语言,原始SQL,......).所以代替:
public class FooDaoImpl extends AbstractDao<Foo> {
...
public Collection<Foo> getByCriteria(Criteria criteria) {
...
}
}
public class FooBusinessImpl {
...
public void doSomethingWithFoosBetween(Date from, Date to) {
...
Criteria criteria = ...;
// Build your criteria to get only foos between from and to
Collection<Foo> foos = fooDaoImpl.getByCriteria(criteria);
...
}
public void doSomethingWithActiveFoos() {
...
Criteria criteria = ...;
// Build your criteria to filter out passive foos
Collection<Foo> foos = fooDaoImpl.getByCriteria(criteria);
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
我会做:
public class FooDaoImpl {
...
public Collection<Foo> getFoosBetween(Date from ,Date to) {
// build and execute query according to from and to
}
public Collection<Foo> getActiveFoos() {
// build and execute query to get active foos
}
}
public class FooBusinessImpl {
...
public void doSomethingWithFoosBetween(Date from, Date to) {
...
Collection<Foo> foos = fooDaoImpl.getFoosBetween(from, to);
...
}
public void doSomethingWithActiveFoos() {
...
Collection<Foo> foos = fooDaoImpl.getActiveFoos();
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
虽然有人可能会认为我正在将一些业务逻辑推到DAO层,但对我来说这似乎是一种更好的方法:将ORM实现更改为替代实现会更容易.想象一下,例如,出于性能原因,您需要Foo使用原始JDBC 来读取某些特定于供应商的扩展:使用通用DAO方法,您需要更改业务和DAO层.使用这种方法,您只需重新实现DAO层.
好吧,你总是可以告诉你的DAO层做你想做的事情.拥有类似于cleanUpDatasourceCacheDAO层的方法,或类似的东西(甚至是针对不同对象的一组这些方法),对我来说并不是一种不好的做法.
然后,您的服务层就可以调用该方法,而无需考虑DAO所做的工作.使用直接JDBC调用的特定实现在该方法中不起作用.
| 归档时间: |
|
| 查看次数: |
3127 次 |
| 最近记录: |