我一直在使用 DAO 模式来访问我一直在构建的应用程序中的持久层。
我已经实现的其中一件事是围绕我的 DAO 实现进行“包装”以进行验证。包装器将我的 DAO 实例作为构造函数参数,并实现与 DAO 类似的接口(interface),除了抛出的异常类型。
例如:
业务逻辑接口(interface)
public interface UserBLInt {
private void assignRightToUser(int userId, int rightId) throws SomeAppException;
}
DAO 接口(interface)
public interface UserDAOInt {
private void assignRightToUser(int userId, int rightId) throws SomeJPAExcption;
}
业务逻辑实现
public class UserBLImpl implements UserBLInt {
private UserDAOInt userDAO;
public UserBLImpl(UserDAOInt userDAO){
this.userDAO = userDAO;
}
@Override
private void assignRightToUser(int userId, int rightId) throws SomeAppException{
if(!userExists(userId){
//throw an exception
}
try{
userDAO.assignRightToUser(userId, rightId);
} catch(SomeJpAException e){
throw new SomeAppException(some message);
}
}
}
DAO 实现
public class UserDAOImpl implements UserDAOInt {
//......
@Override
public void assignRightToUser(int userId, int rightId){
em.getTransaction().begin();
User userToAssignRightTo = em.find(User.class, userId);
userToAssignRightTo.getRights().add(em.find(Right.class, rightId));
em.getTransaction().commit();
}
}
这只是一个简单的示例,但我的问题是,在 DAO 实现中进行另一项检查以确保在添加 >对,但是,作为一名程序员,我看到了空指针的机会。
显然,我可以在实体管理器上调用 find 之后添加空检查,如果返回空则抛出异常,但这就是将 DAO 包装在业务逻辑实现中的全部目的,以便预先完成所有验证工作,因此 DAO 代码是干净的,并且根本不需要在空检查或逻辑方面做太多事情。因为我有 DAO 的包装器,所以在 DAO 中进行 null 检查仍然是个好主意吗?我知道理论上可以在业务逻辑调用和 dao 调用之间删除对象,这不太可能,而且检查 null 似乎是重复的工作。对于这种情况,最佳做法是什么?
编辑:
这看起来像是一个合适的 DAO 修改吗?
public EntityManager beginTransaction(){
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
return entityManager;
}
public void rollback(EntityManager entityManager){
entityManager.getTransaction().rollback();
entityManager.close();
}
public void commit(EntityManager entityManager){
entityManager.getTransaction().commit();
entityManager.close();
}
最佳答案
DAO,虽然现在有点通用和过度使用的术语,但(通常)意在抽象数据层(因此除其他好处外,它可以在不接触应用程序其余部分的情况下进行更改)。
不过,看起来您的 DAO 实际上所做的不仅仅是抽象数据层。在:
public class UserDAOImpl implements UserDAOInt {
......
@Override
public void assignRightToUser(int userId, int rightId){
em.getTransaction().begin();
User userToAssignRightTo = em.find(User.class, userId);
userToAssignRightTo.getRights().add(em.find(Right.class, rightId));
em.getTransaction().commit();
}
}
您的 DAO 知道业务逻辑。它知道向用户分配权限就是在权限列表中添加权限。 (似乎很明显,分配权限只是将其添加到列表中,但想象一下,这在未来可能会变得更加复杂,并对其他用户和权限等产生副作用。)
所以这个赋值不属于DAO。应该在业务层。您的 DAO 应该只有类似 userDAO.save(user) 的东西,业务层在完成设置权限和内容后会调用它。
另一个问题:您的交易过于本地化。这几乎不是交易。
请记住事务是一个业务单元,您在其中执行原子(“批处理”)业务工作,而不仅仅是因为 EntityManager 使您打开的事务。
我的意思是,从代码的角度来说,应该是业务层主动开启事务,而不是DAO(实际上,DAO应该有“开启事务”的服务——方法——会被调用)。
然后考虑在业务层中打开事务:
public class UserBLImpl implements UserBLInt {
...
@Override
private void assignRightToUser(int userId, int rightId) throws SomeAppException{
userDAO.beginTransaction(); // or .beginUnitOfWork(), if you wanna be fancy
if(!userExists(userId){
//throw an exception
// DON'T FORGET TO ROLLBACK!!! before throwing the exception
}
try{
userDAO.assignRightToUser(userId, rightId);
} catch(SomeJpAException e){
throw new SomeAppException(some message);
}
userDAO.commit();
}
}
现在,对于您的问题:数据库在 userExists() if 和 userDAO 之间变化的风险仍然存在。 .. 但你有选择:
(1)锁定用户,直到交易结束;或 (2) 顺其自然。
1:如果用户在这两个命令之间被搞砸的风险很高(比如你的系统有很多并发用户)并且如果这个问题发生了那将是一件大事,那么考虑锁定 整个交易的用户;也就是说,如果我开始使用它,则没有其他事务可以更改它。
2:另一种可能性,你会认为这是最常见的方法,如果你正在处理具有约束检查的 SQL DB,例如 UNIQUE,只是让 DAO 异常吹走。我的意思是,这将是一件非常罕见且几乎不可能发生的事情,您不妨通过接受它可能发生来处理它,您的系统只会显示一条好消息,例如“出了点问题,请重试”- - 这只是基本成本与 yield 的比重。
更新:
程序化事务处理可能很棘手(难怪使用声明式替代方案,例如 Spring 和 EJB/CDI)。尽管如此,我们并不总是有机会使用它们(也许您正在调整遗留系统,谁知道呢)。所以这里有一个建议:https://gist.github.com/acdcjunior/94363ea5cdbf4cae41c7
关于java - DAO 实现的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29525312/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/