spring的事务控制应该说是所有用spring的项目中必不可少的东西。在我所经历过的所有用spring的项目中,IOC和事务控制是必用的。其它的一些东西,根据项目不同会有所选择。为什么要用spring的这两个呢?使用IOC可以让我们的代码进行完全的松耦合。而事务控制,可以让我们基本上在写代码的时候短暂的忘记事务的存在。专心于业务层的实现。下面给出一个spring 事务控制的例子。首页是Action层的代码:

public 
   String createUser()  
  throws 
   Exception  
  ... 
  {
        user = new User();
        user.setUsername("Gavin");
        user.setPassword("123");
        user.setUserDetail(new UserDetail());    
        
        if (logger.isDebugEnabled()) ...{
            logger.debug("创建一个新的用户. " + user.toString());
        }
        
        try ...{
            userService.saveUser(user);

        } catch (Exception e) ...{
            if (logger.isDebugEnabled()) ...{
                logger.debug("用户操作出错. " + e);
            }
        }
        
        return Action.SUCCESS;
    }

Action层只是简单的去调用service层,为了使例子简单,我去掉了一些不必要的东西。只剩下核心的一些。下面给出service层的代码(所有接口用处不大,不给出来)。


package    com.websidesoft.service.impl;

   import 
   org.apache.commons.logging.Log;
   import 
   org.apache.commons.logging.LogFactory;

   import 
   com.websidesoft.dao.iface.FriendDAO;
   import 
   com.websidesoft.dao.iface.UserDAO;
   import 
   com.websidesoft.entities.User;
   import 
   com.websidesoft.exception.WSSException;
   import 
   com.websidesoft.service.iface.UserService;

   public 
    
  class 
   UserServiceManager  
  implements 
   UserService  
  ... 
  {
    private static final Log logger = LogFactory.getLog(UserServiceManager.class);
    
    private FriendDAO friendDao;
    private UserDAO userDao;
    

    public void deleteUser(int userId) throws WSSException ...{
    }

    public User getUser(int userId) throws WSSException ...{
        return null;
    }

    public void saveUser(User user) throws WSSException ...{
        userDao.saveUser(user);
        
        try ...{
            friendDao.saveFriend(user);
        } catch (Exception e) ...{
            if (logger.isDebugEnabled()) ...{
                logger.debug("保存friend出错. " + e);
            }            
        }
        
//        throw new RuntimeException("出错.............");
    }
    
    public void updateUser(User user) throws WSSException ...{
        
    }

    public FriendDAO getFriendDao() ...{
        return friendDao;
    }

    public void setFriendDao(FriendDAO friendDao) ...{
        this.friendDao = friendDao;
    }

    public UserDAO getUserDao() ...{
        return userDao;
    }

    public void setUserDao(UserDAO userDao) ...{
        this.userDao = userDao;
    }

}

service是重点,给出了所有service层的代码。先给出所有的代码,之后再来详细说明。下面是DAO层代码:

 

package    com.websidesoft.dao.impl;

   import    java.util.HashMap;
   import    java.util.Map;

   import    org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
   import    org.springframework.jdbc.core.support.JdbcDaoSupport;

   import    com.websidesoft.dao.iface.UserDAO;
   import    com.websidesoft.entities.User;
   import    com.websidesoft.exception.DataAccessException;

   public     
  class 
   UserDAOImpl  
  extends 
   JdbcDaoSupport  
  implements 
   UserDAO  
  ... 
  {

    public void deleteUser(int userId) throws DataAccessException ...{
    }

    public User getUser(int userId) throws DataAccessException ...{
        return null;
    }

    public void saveUser(User user) throws DataAccessException ...{
        String sql = "insert into wss_users(username, password) values (:username, :password)";
        
        NamedParameterJdbcTemplate pstmt = new NamedParameterJdbcTemplate(this.getJdbcTemplate().getDataSource());
        Map nameParameters = new HashMap();
        nameParameters.put("username", user.getUsername());
        nameParameters.put("password", user.getPassword());
    
        pstmt.update(sql, nameParameters);
    }

    public void updateUser(User user) throws DataAccessException ...{
    }
}   

   package    com.websidesoft.dao.impl;

   import    org.springframework.jdbc.core.support.JdbcDaoSupport;

   import    com.websidesoft.dao.iface.FriendDAO;
   import    com.websidesoft.exception.DataAccessException;

   public     
  class 
   FriendDAOImpl  
  extends 
   JdbcDaoSupport  
  implements 
   FriendDAO  
  ... 
  {

    public void saveFriend(Object o) throws DataAccessException ...{
        throw new NullPointerException("不能传入空的参数.");
    }
}

为了简单和测试,我在FriendDAO中直接抛出异常。下面给出xml配置文件,只是核心的,还有一些bean的ioc就不写出来了。



<?   xml versinotallow="1.0" encoding="UTF-8"   ?>   
   <   beans    xmlns 
  ="http://www.springframework.org/schema/beans" 
  
         xmlns:xsi   ="http://www.w3.org/2001/XMLSchema-instance"   
         xmlns:aop   ="http://www.springframework.org/schema/aop"   
         xmlns:tx   ="http://www.springframework.org/schema/tx"   
          xmlns:jee   ="http://www.springframework.org/schema/jee"   
         xsi:schemaLocation   ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
           http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"   >   

    
          <   bean    id 
  ="dataSource" 
   class 
  ="org.springframework.jndi.JndiObjectFactoryBean" 
  > 
  
           <   property    name 
  ="jndiName" 
   value 
  ="java:comp/env/jdbc/wss" 
  /> 
  
       </   bean   > 
  
    
       <   bean    id 
  ="transactionManager" 
   class 
  ="org.springframework.jdbc.datasource.DataSourceTransactionManager" 
  > 
  
           <   property    name 
  ="dataSource" 
   ref 
  ="dataSource" 
  /> 
  
       </   bean   > 
  
    
       <   tx:advice    id 
  ="txAdvice" 
   transaction-manager 
  ="transactionManager" 
  > 
  
           <   tx:attributes   > 
  
               <   tx:method    name 
  ="save*" 
  /> 
  
               <   tx:method    name 
  ="get*" 
  /> 
  
           </   tx:attributes   > 
  
       </   tx:advice   > 
  
    
       <   aop:config   > 
  
           <   aop:pointcut    id 
  ="userServicePointcut" 
   expression 
  ="execution(* com.websidesoft.service.iface.UserService.*(..))" 
  /> 
  
           <   aop:advisor    advice-ref 
  ="txAdvice" 
   pointcut-ref 
  ="userServicePointcut" 
  /> 
  
           <   aop:aspect    id 
  ="userAspect" 
   ref 
  ="userLog" 
  > 
  
                 <   aop:before    pointcut 
  ="execution(* com.websidesoft.service.iface.UserService.*(..)) and args(user)" 
   method 
  ="saveUser" 
  /> 
  
           </   aop:aspect   > 
  
       </   aop:config   > 
  
    
    
       <!--    DAO层    --> 
  
       <   bean    id 
  ="userDao" 
   class 
  ="com.websidesoft.dao.impl.UserDAOImpl" 
  > 
  
           <   property    name 
  ="dataSource" 
   ref 
  ="dataSource" 
  /> 
  
       </   bean   > 
  
    
       <   bean    id 
  ="friendDao" 
   class 
  ="com.websidesoft.dao.impl.FriendDAOImpl" 
  > 
  
           <   property    name 
  ="dataSource" 
   ref 
  ="dataSource" 
  /> 
  
       </   bean   > 
  
   </   beans   >

上面给出了这个例子的所有代码。下面首先说明一下事务控制的部份。核心的事务控制部份如下:



spring控制事务提交 spring 事务控制_spring

<   bean    id   ="dataSource"    class 
  ="org.springframework.jndi.JndiObjectFactoryBean" 
  > 
  
           <   property    name   ="jndiName" 
   value 
  ="java:comp/env/jdbc/wss" 
  /> 
  
       </   bean   >   
    
       <   bean    id   ="transactionManager" 
   class 
  ="org.springframework.jdbc.datasource.DataSourceTransactionManager" 
  > 
  
           <   property    name   ="dataSource" 
   ref 
  ="dataSource" 
  /> 
  
       </   bean   >   
    
       <   tx:advice    id   ="txAdvice" 
   transaction-manager 
  ="transactionManager" 
  > 
  
           <   tx:attributes   >   
               <   tx:method    name   ="save*" 
  /> 
  
               <   tx:method    name   ="get*" 
  /> 
  
           </   tx:attributes   >   
       </   tx:advice   >


上面的配置实现了以容器的方式配置数据源。对数据源进行事务管理。看一下service层的代码:


public       void    saveUser(User user)    throws    WSSException  
  ... 
  {
        userDao.saveUser(user);
        
        try ...{
            friendDao.saveFriend(user);
        } catch (Exception e) ...{
            if (logger.isDebugEnabled()) ...{
                logger.debug("保存friend出错. " + e);
            }            
        }
        
//        throw new RuntimeException("出错.............");
    }

在上面的代码中,如果出现错误,将抛出WSSException异常。这个异常是实现了Exception的全局异常。spring在对事务控制时,只对运行时异常和未检测异常才会进行事务的rollback,也就是说当抛出检测异常将不会被rollback。看上面的例子,我对friendDao.saveFriend(user)进行了try catch动作。因为在friendDao中,我直接抛出抛常。也就是说如果friendDao出错,将不能影响到用户的正常注册。上面的异常不会导致事务回滚。上面的代码运行进,将会用户正常的注册。在下面,我把一行代码注释了,throw new RuntimeException("出错.............");这一代码有什么作用呢?这一句最重要的作用就是,如果打开,那么所有的事务将进行rollback操作。也就是说保存用户将会出错。不会保存成功。

上面只是简单的举了个例子来说明spring2.0中事务控制。当然,还可以控制指定哪些异常将会导致回滚动作。只需要在事务控制的xml中加上rollback-for="异常全名"即可。