关于DAO层的异常处理

Aaronbamboo 2010-01-25 10:46:24
本人在写DAO层时用到了HibernateTemplate,它的所有接口都统一抛出DataAccessException。现在的问题是比如说增加一个用户时用户名重复,这样一个异常,大家觉得应该是在DAO层抛出,还是Service层抛出。
...全文
608 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hackersun12345 的回复:]
引用 5 楼 aaronbamboo 的回复:
类似名字重复的错误,有这样的情况:
数据库定义了唯一键,则HibernateTemplate抛出异常DataAccessException,但是由于Sevice层无法区别具体的异常类型。该如何处理?

是在保存前先判断是否有该用户名的用户存在(这里应该在一个事务中处理);还是失败了再判断是否因为用户已经存在?

最好不要在异常中处理业务逻辑,除非项目特殊需要,也就是正常的业务流水线应该是先验证后操作。
对于你的问题建议先判断后插入DB,尽管这样会多执行一条SQL语句,但更符合通常作法。
[/Quote]

那么是否应该把验证和插入DB的操作作为一个事务来处理呢?
hackersun12345 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 aaronbamboo 的回复:]
类似名字重复的错误,有这样的情况:
数据库定义了唯一键,则HibernateTemplate抛出异常DataAccessException,但是由于Sevice层无法区别具体的异常类型。该如何处理?

是在保存前先判断是否有该用户名的用户存在(这里应该在一个事务中处理);还是失败了再判断是否因为用户已经存在?
[/Quote]
最好不要在异常中处理业务逻辑,除非项目特殊需要,也就是正常的业务流水线应该是先验证后操作。
对于你的问题建议先判断后插入DB,尽管这样会多执行一条SQL语句,但更符合通常作法。
znwuyan318 2010-01-25
  • 打赏
  • 举报
回复
直接在业务层 做重复判断貌似好点
Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
或者干脆唯一键也不设了,直接业务层先自己判断?
Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
类似名字重复的错误,有这样的情况:
数据库定义了唯一键,则HibernateTemplate抛出异常DataAccessException,但是由于Sevice层无法区别具体的异常类型。该如何处理?

是在保存前先判断是否有该用户名的用户存在(这里应该在一个事务中处理);还是失败了再判断是否因为用户已经存在?
mengxq 2010-01-25
  • 打赏
  • 举报
回复
通过Service层抛出
dinghun8leech 2010-01-25
  • 打赏
  • 举报
回复
dao层负责基本的数据与数据库交互,最好不要混进业务逻辑,某字段不可插入重复值的判断应该放在service层,所以要抛异常,也是在service层抛。
此类信息个人觉得还是以返回值的方式告诉调用端就足够了,不一定要自己整一个异常抛出。
APOLLO_TS 2010-01-25
  • 打赏
  • 举报
回复
不冲突,都抛出,DataAccessException是对SQlException包装了,

服务调用DAO也一样,服务层异常包装DAO层异常,分工明确,即便那天为了提高性能直接调用DAO也埋下伏笔。

bart1988 2010-01-25
  • 打赏
  • 举报
回复
这样的异常应该通过Service层抛出。应该判断用户名是否重复与DAO数据操作层没直接关联而是属于一种业务逻辑,所以其异常应该由Service层抛出。
zm_hs 2010-01-25
  • 打赏
  • 举报
回复
在插入记录前先弄个方法验证名字是否已存在多好啊!何必抛啥异常
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 aaronbamboo 的回复:]
zhoche2008 的方法很有道理。不知道zhoche2008兄在项目中是如何设计异常的处理方式的?
[/Quote]
过奖了,无非就是上面的几种方式了,先弄个自定义异常类,然后需要什么特殊的异常就直接从上面继承即可,SPRING的异常处理方式很值得借鉴,抄抄就行了
记得以前做过一个项目,不同的情况抛出不同的自定义异常,然后由框架统一做判断,
比如插入时没有权限抛出Exception1,插入重复抛出Exception2,等等
Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
zhoche2008 的方法很有道理。不知道zhoche2008兄在项目中是如何设计异常的处理方式的?
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
或者你还可以这样
public void saveUser(User newUser){
try{
dao.saveUser(newUser);
}
catch(DataAccessException e){
if(e instanceof DataIntegrityViolationException){
throw new 自定义Exception("用户重复");
}else if(e instanceof DataIntegrityViolationException){
throw new 自定义Exception("其他信息1");
}
else if(e instanceof DataRetrievalFailureException){
throw new 自定义Exception("其他信息2");
}else{
throw new 自定义Exception("其他信息3");
}
}
}

上面代码的前提是,你必须知道,在插入时遇到重复约束和其他的错误抛出的具体异常类型具体是什么,这个你可以做个试验用断点调试一下
fevergreenliu 2010-01-25
  • 打赏
  • 举报
回复
在service层,对所插入操作进行加锁,保证串行
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 aaronbamboo 的回复:]
引用 17 楼 zhoche2008 的回复:

那就在SERVICE中判断异常类型,然后转换成自定义异常,示例代码
public void saveUser(User newUser){
try{
dao.saveUser(newUser);
}
catch(Hibernate用户重复时Exception e){
throw new 自定义Exception("用户插入失败:用户"+newUser.getUserId()+"重复");
}
catch(HibrenateOtherException e){
throw new 自定义Exception("用户插入失败:"+e.getMessage());
}
}


这在Hibernate中好像可行,我还想问一下,如果使用了Spring的HibernateTemplate,它的所有方法都只抛出DataAccessException,这种情况下我们应该如何处理才好呢?
[/Quote]

据我所知,框架自定义的异常都不会把本身的原始异常类丢失,spring中所有异常都是DataAccessException的子类,下面的DataAccessException源码【抽象类】:
public abstract class DataAccessException extends NestedRuntimeException {

/**
* Constructor for DataAccessException.
* @param msg the detail message
*/
public DataAccessException(String msg) {
super(msg);
}

/**
* Constructor for DataAccessException.
* @param msg the detail message
* @param cause the root cause (usually from using a underlying
* data access API such as JDBC)
*/
public DataAccessException(String msg, Throwable cause) {
//很明显,这里提供把原始异常做为参数的构造方法
super(msg, cause);
}

}

所以你可以在SERVICE中拿到DATAACCESSException后,再判断他的子类型,或者直接获取原始异常,如

public void saveUser(User newUser){
try{
dao.saveUser(newUser);
}
catch(DataAccessException e){
Throwable thr=e.getRootCause();
if(thr.getMessage().contains("重复时的异常")){
throw new 自定义Exception("用户重复");
}else{
throw new 自定义Exception("其他信息");
}
}
}

Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 zhoche2008 的回复:]

那就在SERVICE中判断异常类型,然后转换成自定义异常,示例代码
public void saveUser(User newUser){
try{
dao.saveUser(newUser);
}
catch(Hibernate用户重复时Exception e){
throw new 自定义Exception("用户插入失败:用户"+newUser.getUserId()+"重复");
}
catch(HibrenateOtherException e){
throw new 自定义Exception("用户插入失败:"+e.getMessage());
}
}
[/Quote]

这在Hibernate中好像可行,我还想问一下,如果使用了Spring的HibernateTemplate,它的所有方法都只抛出DataAccessException,这种情况下我们应该如何处理才好呢?
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
如果DAO中异常类型是一样的,那总有不一样错误信息的吧
public void saveUser(User newUser) {
try {
dao.saveUser(newUser);
} catch (HibrenateException e) {
if (e.getMessage().contains("插入重复用户时抛出的异常信息串")) {
throw new 自定义Exception("用户插入失败:用户" + newUser.getUserId() + "重复");
} else {
throw new 自定义Exception("用户插入失败:" + e.getMessage());
}
}
}
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 aaronbamboo 的回复:]
引用 15 楼 zhoche2008 的回复:
引用 14 楼 aaronbamboo 的回复:
引用 13 楼 zhoche2008 的回复:
以下写在dao
public void saveUser(User user){
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
}

public User findUserById(Integer userId) {
Session session = sessionFactory.openSession();
User user = (User) session.get(User .class, userId);
session.close();
return user;
}

以下写在service
public void saveUser(User newUser){
  User user =dao.findUserById(newUser.getUserId());
if(user !=null){
throw new Exception("用户"+newUser.getUserId()+"重复");
}
dao.saveUser(newUser);
}


针对你的代码,如果判断用户的确不存在,但是当向数据库插入用户时,其他并它的线程已经插入了改用户,结果当前线程还是遇到了用户已经存在的问题,但是Hibernate抛出的应该是HibernateException,不知道这种情况是否需要考虑?


说的有道理,那就在不能重复的键上面创建唯一约束吧,这个就不怕线程了,SERVICE层也不用做判断,直接在DAO插入即可


这样的话,从HibernateException似乎无法判断具体的错误信息,也就是说在业务层无法转化成自定义的异常?
[/Quote]
那就在SERVICE中判断异常类型,然后转换成自定义异常,示例代码
public void saveUser(User newUser){
try{
dao.saveUser(newUser);
}
catch(Hibernate用户重复时Exception e){
throw new 自定义Exception("用户插入失败:用户"+newUser.getUserId()+"重复");
}
catch(HibrenateOtherException e){
throw new 自定义Exception("用户插入失败:"+e.getMessage());
}
}
Aaronbamboo 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 zhoche2008 的回复:]
引用 14 楼 aaronbamboo 的回复:
引用 13 楼 zhoche2008 的回复:
以下写在dao
public void saveUser(User user){
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
}

public User findUserById(Integer userId) {
Session session = sessionFactory.openSession();
User user = (User) session.get(User .class, userId);
session.close();
return user;
}

以下写在service
public void saveUser(User newUser){
  User user =dao.findUserById(newUser.getUserId());
if(user !=null){
throw new Exception("用户"+newUser.getUserId()+"重复");
}
dao.saveUser(newUser);
}


针对你的代码,如果判断用户的确不存在,但是当向数据库插入用户时,其他并它的线程已经插入了改用户,结果当前线程还是遇到了用户已经存在的问题,但是Hibernate抛出的应该是HibernateException,不知道这种情况是否需要考虑?


说的有道理,那就在不能重复的键上面创建唯一约束吧,这个就不怕线程了,SERVICE层也不用做判断,直接在DAO插入即可
[/Quote]

这样的话,从HibernateException似乎无法判断具体的错误信息,也就是说在业务层无法转化成自定义的异常?
zhoche2008 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 aaronbamboo 的回复:]
引用 13 楼 zhoche2008 的回复:
以下写在dao
public void saveUser(User user){
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
}

public User findUserById(Integer userId) {
Session session = sessionFactory.openSession();
User user = (User) session.get(User .class, userId);
session.close();
return user;
}

以下写在service
public void saveUser(User newUser){
  User user =dao.findUserById(newUser.getUserId());
if(user !=null){
throw new Exception("用户"+newUser.getUserId()+"重复");
}
dao.saveUser(newUser);
}


针对你的代码,如果判断用户的确不存在,但是当向数据库插入用户时,其他并它的线程已经插入了改用户,结果当前线程还是遇到了用户已经存在的问题,但是Hibernate抛出的应该是HibernateException,不知道这种情况是否需要考虑?
[/Quote]

说的有道理,那就在不能重复的键上面创建唯一约束吧,这个就不怕线程了,SERVICE层也不用做判断,直接在DAO插入即可
加载更多回复(5)

67,550

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧