Jakarta ee JPA数据访问对象-异常处理和回滚
我想知道在数据访问对象中处理异常的最佳方法是什么,我对产品质量代码感兴趣 例如Jakarta ee JPA数据访问对象-异常处理和回滚,jakarta-ee,jpa,exception-handling,dao,rollback,Jakarta Ee,Jpa,Exception Handling,Dao,Rollback,我想知道在数据访问对象中处理异常的最佳方法是什么,我对产品质量代码感兴趣 例如 public UserDaoImpl implements UserDao{ @PersistenceContext private EntityManager em; void save(User user){ em.persist(user); } User getById(long id){ return em.find(User.class
public UserDaoImpl implements UserDao{
@PersistenceContext
private EntityManager em;
void save(User user){
em.persist(user);
}
User getById(long id){
return em.find(User.class,id);
}
}
比如说,我在某个地方有一个RegisterService,我希望在某个时候将用户保存到数据库中。每个用户都需要一封独特的电子邮件。
您如何检查这一点,以及该代码的去向?
在持久化之前,我们是否使用查询检查保存方法中是否已经有该电子邮件的用户?或者该代码会被发送到服务吗?或者我们试着抓住一些例外
但就我所知,对于例外情况,我们永远无法确定到底发生了什么,我们可以尝试捕获ConstraintViolationException,但这并不能明确告诉我们发生了什么
它在产品质量代码中的表现如何?这与您的知识和“风格”密切相关;人们做这件事的方式不同,有些是对的,有些是错的 我来自一个从不使用异常进行流控制的世界,这意味着:我不会恢复抛出异常的情况。当流程中发生某些事情时,我总是让它进入最高级别,有时重新抛出以添加更多的价值/意义/语义信息。因此,例如,在您的
save(User-User)
中,原因/问题是什么并不重要,因为它只是失败了。我不认为有一组异常比其他异常更重要……这就是为什么我可以更进一步,并不真正需要/使用所有异常类型,因为仅表示一种行为就足够了(exception
)-在这里,人们不同意(有时不考虑…“为什么不止一种”?)
在您的情况下,人们通常会:
void save(User user) {
try {
em.persist(user);
} catch (SomeExceptionType e) {
log.error("something here");
// What now here, huh?
}
}
其他人可能会说,最好有不同类型的人“知道发生了什么”,比如:
…这和用它们来控制流量没有什么不同
希望能有帮助。这可能是一件“正在进行的事情”,但如果这种方法适合你的世界,我希望你能得到这个想法
建议
使final
成为您的UserDaoImpl
(如果您知道没有其他人从中扩展)。您的方法应该是private
和final
以及参数。明智地使用public
,即使是在类级别,有时我们也不会在同一个包之外使用它们
public final UserDaoImpl implements UserDao {
// Grrrr, can't make 'em' final...that's because DI is an
// anti-pattern but that's another story
@PersistenceContext
private EntityManager em;
private void save(final User user){
em.persist(user);
}
private User getById(final long id){
return em.find(User.class, id);
}
}
比如说,我在某个地方有一个RegisterService,我希望在某个时候将用户保存到数据库中。每个用户都需要一封独特的电子邮件。您如何检查这一点,以及该代码的去向
在插入时在同一事务中检查它,并引发触发完全回滚的自定义异常
签入同一事务将保证DB在插入期间不会导致约束冲突异常。建议您的“DAO”实际上是一个@无状态的
EJB(基于您用[JavaEE]而不是[spring]标记问题的事实),那么客户端的每个方法调用默认情况下都算作一个事务
抛出特定于定制服务层的异常会将前端(即调用该业务服务方法的人,如JSF、JAX-RS、Spring MVC、JSP/Servlet等)与底层持久性层分离。换句话说,前端代码库完全没有javax.persistence.*
imports/dependencies。建议您使用EJB作为服务层API,然后使用注释注释自定义异常
例如
然后,在前端,只需捕获自定义服务层特定的异常(我们现在可以确定这正是导致异常的预期意外情况),并通过向最终用户显示“嘿,你已经注册了!也许你想登录或重置密码?”消息来进行相应的处理
另见:
public final UserDaoImpl implements UserDao {
// Grrrr, can't make 'em' final...that's because DI is an
// anti-pattern but that's another story
@PersistenceContext
private EntityManager em;
private void save(final User user){
em.persist(user);
}
private User getById(final long id){
return em.find(User.class, id);
}
}
@Stateless
public class UserService {
@PersistenceContext
private EntityManager em;
public User findByEmail(String email) {
List<User> users = em.createQuery("SELECT u FROM User u WHERE email = :email", User.class)
.setParameter("email", email)
.getResultList();
return users.isEmpty() ? null : users.get(0);
}
public void register(User user) {
if (findByEmail(user.getEmail()) != null) {
throw new DuplicateEntityException();
}
em.persist(user);
}
// ...
}
@ApplicationException(rollback=true)
public class DuplicateEntityException extends RuntimeException {}