论坛首页 Java版 Spring

spring+Hibernate中异常如何处理

浏览 11252 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2006-01-19
现在项目中用到了spring+hibernate的框架。但有关其中的异常处理还有点不明白。

现在的框架是这样:
WEB <-> Service <-> DAO <-> Database

DAO是继承HibernateDaoSupport。

[code:1]public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
   
    public User addUser(User user) throws DataAccessException {
        this.getHibernateTemplate().save(user);
        Hibernate.initialize(user);
        return user;
    }
...

}[/code:1]

Service层是业务方法,调用DAO的功能:

[code:1]public class UserServiceImpl implements UserService {

    private UserDao userDao;
   
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }   
   
    public User addUser(User user) {
        return userDao.addUser(user);
    }
...
}[/code:1]

Web层采用struts,action中直接调用service的各种方法。

service中的事务采用了声明式事物:
[code:1]    <bean id="userServiceTarget" class="com.javaeye.service.impl.UserServiceImpl">
        <property name="userDao"><ref local="userDao"/></property>
    </bean>
       
    <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref local="transactionManager"/></property>
        <property name="target"><ref local="userServiceTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="delete*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>[/code:1]

以上是大概的架构。现在的问题是如何将spring抛出的异常转换成自己的异常。在DAO中,各种调用HibernateTemplate的方法好像都抛出DataAccessException,但我在DAO中的代码,好像不能直接catch这个异常:

[code:1]try {
        this.getHibernateTemplate().save(user);
        Hibernate.initialize(user);
        return user;
} catch (DataAccessException ex) {
  ...
}[/code:1]

好像不会跳到异常处。 只能让DAO将异常往上抛给service,service也没法直接catch,直接抛给要调用service的action,action中catch DataAccessException,然后转换成自己的Exception。

不知道各位是怎么处理spring中的异常的?
   
最后更新时间:2006-01-16
Spring不是已经帮你把所有的异常都转化成DataAccessException了嘛,你还包装啥呢?
   
0 请登录后投票
最后更新时间:2006-01-16
//先自定义一个异常
[code:1]public class FooException extends DataAccessException{
     public FooException(String msg){
        this.msg = msg;
    }
    //.....
}[/code:1]


在struts-config.xml声明一下
[code:1]   <global-exceptions>
<exception key="global.data.access.exception"
path="/pages/error.jsp"
scope="request"
type="yourpackage.FooException "/>
</global-exceptions>[/code:1]

事务:
[code:1]    <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref local="transactionManager"/></property>
        <property name="target"><ref local="userServiceTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly,-FooException</prop>
                <prop key="add*">PROPAGATION_REQUIRED,-FooException</prop>
                <prop key="update*">PROPAGATION_REQUIRED,-FooException</prop>
                <prop key="delete*">PROPAGATION_REQUIRED,-FooException</prop>
            </props>
        </property>
    </bean>[/code:1]

捕获:
[code:1]try {
  User user = (User)this.getHibernateTemplate().load(User.class, userId);
} catch (FooException ex) {
  ...
}[/code:1]
   
0 请登录后投票
最后更新时间:2006-01-16
我按照你的方法,不管是DAO还是service,还是不能执行到catch里面的代码。
   
0 请登录后投票
最后更新时间:2006-01-16
AndyTse 写道
我按照你的方法,不管是DAO还是service,还是不能执行到catch里面的代码。


[code:1]try {
  User user = (User)this.getHibernateTemplate().load(User.class, userId);
} catch (Exception ex) {
   throws new FooException(ex.getMessage());
}[/code:1]

    首先你要确定你抛出的什么类型的异常?DataAccessException是RuntimeException, 属于uncheck异常! 如果你程序抛的是VirtualMacthineError或SQLException,IOException是check异常当然捕获不到。建议你设个断点看看出错的代码抛出的什么类型的异常再用相应的异常catch....
   
0 请登录后投票
最后更新时间:2006-01-17
我在做testcase,故意insert两条主键一样的记录,报的错是:
hibernateTest.UserTest)org.springframework.dao.DataIntegrityViolationException:

在代码中捕获的是DataAccessException,但没有作用。
   
0 请登录后投票
最后更新时间:2006-01-17
AndyTse 写道
我在做testcase,故意insert两条主键一样的记录,报的错是:
hibernateTest.UserTest)org.springframework.dao.DataIntegrityViolationException:

在代码中捕获的是DataAccessException,但没有作用。



java.lang.Object
  |_java.lang.Throwable
     &nbsp|_ java.lang.Exception
     &nbsp&nbsp   |_  java.lang.RuntimeException
     &nbsp&nbsp&nbsp      |_   org.springframework.core.NestedRuntimeException
     &nbsp&nbsp&nbsp&nbsp         |_    org.springframework.dao.DataAccessException
     &nbsp&nbsp&nbsp&nbsp&nbsp            |_   org.springframework.dao.DataIntegrityViolationException

&nbsp&nbspDataIntegrityViolationException是继承DataAccessException。看看spring源码里的HibernateTemplate类,它把DataAccessException异常都往上层调用者throws.

引用
注意看注释:checked HibernateExceptions into unchecked DataAccessException


   所以DataAccessException应该在service层中被catch。重现了你的重复主键test,是可以捕获的,只需你的DaoImpl类中这样改一下,在serviceImpl调用这个DAO处catch就可以了!:
    [code:1]public void insertObject(//....) throws DataAccessException{
}[/code:1]

我的测试环境是:spring2.0 + hibernate3.1+ mysql5.1
   
0 请登录后投票
最后更新时间:2006-01-17
我试了下还是无效啊,我把我代码贴出来:

applicationContext.xml:
[code:1]    <!-- User Service Definition -->
    <bean id="userServiceTarget" class="com.javaeye.service.impl.UserServiceImpl">
        <property name="userDao"><ref local="userDao"/></property>
    </bean>
       
    <!-- Transactional proxy for the User Service -->
    <bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref local="transactionManager"/></property>
        <property name="target"><ref local="userServiceTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="delete*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>[/code:1]

UserDaoImpl.java:
[code:1]public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
    public User addUser(User user) throws DataAccessException {
        this.getHibernateTemplate().save(user);
        Hibernate.initialize(user);
        return user;
    }
}[/code:1]

UserServiceImpl.java:
[code:1]    public User addUser(User user) {
        try {
            userDao.addUser(user);
            return user;
        } catch (DataAccessException ex) {
            System.out.println("error..");
            return null;
        }
    }[/code:1]

UserTest.java:

[code:1]    public void testCreateUser() {
        User user = new User();
        user.setUserId(newUserId);
       
        User newUser = userService.addUser(user);
           
        if (newUser != null) {
            assertEquals(newUser.getUserId(), newUserId);
        }
    }[/code:1]

测试结果是:
testCreateUser(hibernateTest.UserTest)org.springframework.dao.DataIntegrityViolationException: Hibernate operation: Could not execute JDBC batch update; SQL [insert into USER (NAME, PASSWORD, EMAIL, EXPIRED_MONTH, LOCK_TIME, LEVEL_ID, DEPT_ID, USER_ID) values (?, ?, ?, ?, ?, ?, ?, ?)]; Duplicate entry 'admin' for key 1; nested exception is java.sql.BatchUpdateException: Duplicate entry 'admin' for key 1
java.sql.BatchUpdateException: Duplicate entry 'admin' for key 1
...

我的环境是spring1.2.6 + Hibernate3 + mysql4.0.

换成spring2也一样。
   
0 请登录后投票
最后更新时间:2006-01-17
但如果捕获DataAccesException的代码放到testCreateUser里面,是可以的。
[code:1]        try {
            User newUser = userService.addUser(user);
            if (newUser != null) {
                assertEquals(newUser.getUserId(), newUserId);
            }           
        } catch (DataAccessException ex) {
            System.out.println("failure"); //主键出错时候,会执行的到。
        }[/code:1]
   
0 请登录后投票
最后更新时间:2006-01-18
AndyTse 写道
我在做testcase,故意insert两条主键一样的记录,报的错是:
hibernateTest.UserTest)org.springframework.dao.DataIntegrityViolationException:

在代码中捕获的是DataAccessException,但没有作用。


在可能出错的地方增加getTemplate.getSession().flush()
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐