• SpringMVC:业务层事务管理


    这里将用到以下几个包:

    引用

    aopalliance-1.0.jar
    commons-collections.jar
    commons-dbcp.jar
    commons-logging-1.1.1.jar
    commons-pool.jar
    jstl.jar
    log4j-1.2.15.jar
    mysql-connector-java-5.1.6-bin.jar
    spring-aop-2.5.6.jar
    spring-beans-2.5.6.jar
    spring-context-2.5.6.jar
    spring-context-support-2.5.6.jar
    spring-core-2.5.6.jar
    spring-jdbc-2.5.6.jar
    spring-tx-2.5.6.jar
    spring-web-2.5.6.jar
    spring-webmvc-2.5.6.jar
    standard.jar


    主要增加了spring-aop-2.5.6.jar的AOP支持包!

    之前我们在AccountService中加入了注解@Transactional标签,但是要想要真正发挥事务作用,还需要一些配置。
    主要需要调整dao.xml文件
    dao.xml-事务管理

    Xml代码
    1. <bean  
    2.     id="transactionManager"  
    3.     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"  
    4.     p:dataSource-ref="dataSource" />  
    5. <tx:annotation-driven  
    6.     transaction-manager="transactionManager" />  
    1. <bean  
    2.     id="transactionManager"  
    3.     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"  
    4.     p:dataSource-ref="dataSource" />  
    5. <tx:annotation-driven  
    6.     transaction-manager="transactionManager" />  


    细化一下AccountService接口方法
    AccountService.java

    Java代码
    1. /**  
    2.  * 2010-1-23  
    3.  */  
    4. package org.zlex.spring.service;   
    5.   
    6. import org.springframework.dao.DataAccessException;   
    7. import org.springframework.transaction.annotation.Transactional;   
    8. import org.zlex.spring.domain.Account;   
    9.   
    10. /**  
    11.  * 账户业务接口  
    12.  *   
    13.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>  
    14.  * @version 1.0  
    15.  * @since 1.0  
    16.  */  
    17. public interface AccountService {   
    18.   
    19.     /**  
    20.      * 获得账户  
    21.      *   
    22.      * @param username  
    23.      * @param password  
    24.      * @return  
    25.      */  
    26.     @Transactional(readOnly = true)   
    27.     Account read(String username, String password);   
    28.   
    29.     /**  
    30.      * 获得账户  
    31.      *   
    32.      * @param id  
    33.      * @return  
    34.      */  
    35.     @Transactional(readOnly = true)   
    36.     Account read(int id);   
    37.   
    38.     /**  
    39.      * 注册用户  
    40.      *   
    41.      * @param account  
    42.      * @return  
    43.      */  
    44.     @Transactional(readOnly = false, rollbackFor = DataAccessException.class)   
    45.     Account register(Account account);   
    46. }  
    1. /** 
    2.  * 2010-1-23 
    3.  */  
    4. package org.zlex.spring.service;  
    5.   
    6. import org.springframework.dao.DataAccessException;  
    7. import org.springframework.transaction.annotation.Transactional;  
    8. import org.zlex.spring.domain.Account;  
    9.   
    10. /** 
    11.  * 账户业务接口 
    12.  *  
    13.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a> 
    14.  * @version 1.0 
    15.  * @since 1.0 
    16.  */  
    17. public interface AccountService {  
    18.   
    19.     /** 
    20.      * 获得账户 
    21.      *  
    22.      * @param username 
    23.      * @param password 
    24.      * @return 
    25.      */  
    26.     @Transactional(readOnly = true)  
    27.     Account read(String username, String password);  
    28.   
    29.     /** 
    30.      * 获得账户 
    31.      *  
    32.      * @param id 
    33.      * @return 
    34.      */  
    35.     @Transactional(readOnly = true)  
    36.     Account read(int id);  
    37.   
    38.     /** 
    39.      * 注册用户 
    40.      *  
    41.      * @param account 
    42.      * @return 
    43.      */  
    44.     @Transactional(readOnly = false, rollbackFor = DataAccessException.class)  
    45.     Account register(Account account);  
    46. }  


    这里我把注解@Transactional调整到了具体的方法上,也就是说这样写的话,凡是加入注解的标注的方法都属于事务配置!
    Account register(Account account);用做用户注册作用!
    @Transactional(readOnly = true)只读属性
    @Transactional(readOnly = false, rollbackFor = DataAccessException.class)只读关闭,遇到DataAccessException异常回滚!如果不对异常进行处理,该异常将一直向上层抛出,直至抛出到页面!
    如果你的Eclipse集成了SpringIDE,你可以观察一下这时的xml配置文件和AccoutServiceImpl.java的变化!


    这次,来个用户注册功能演示,故意在某个位置制造一个异常,看看是否正常回滚!
    先看注册控制器
    RegisterController.java

    Java代码
    1. /**  
    2.  * 2010-2-4  
    3.  */  
    4. package org.zlex.spring.controller;   
    5.   
    6. import java.text.DateFormat;   
    7. import java.text.SimpleDateFormat;   
    8. import java.util.Date;   
    9.   
    10. import org.springframework.beans.factory.annotation.Autowired;   
    11. import org.springframework.beans.propertyeditors.CustomDateEditor;   
    12. import org.springframework.stereotype.Controller;   
    13. import org.springframework.ui.ModelMap;   
    14. import org.springframework.web.bind.WebDataBinder;   
    15. import org.springframework.web.bind.annotation.InitBinder;   
    16. import org.springframework.web.bind.annotation.ModelAttribute;   
    17. import org.springframework.web.bind.annotation.RequestMapping;   
    18. import org.springframework.web.bind.annotation.RequestMethod;   
    19. import org.zlex.spring.domain.Account;   
    20. import org.zlex.spring.service.AccountService;   
    21.   
    22. /**  
    23.  * 用户注册控制器  
    24.  *   
    25.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>  
    26.  * @version 1.0  
    27.  * @since 1.0  
    28.  */  
    29. @Controller  
    30. @RequestMapping(value = "/register.do")   
    31. public class RegisterController {   
    32.   
    33.     @Autowired  
    34.     private AccountService accountService;   
    35.   
    36.     @InitBinder  
    37.     public void initBinder(WebDataBinder binder) {   
    38.         // 忽略字段绑定异常   
    39.         // binder.setIgnoreInvalidFields(true);   
    40.   
    41.         DateFormat format = new SimpleDateFormat("yyyy-MM-dd");   
    42.         binder.registerCustomEditor(Date.class"birthday",   
    43.                 new CustomDateEditor(format, true));   
    44.     }   
    45.   
    46.     @RequestMapping(method = RequestMethod.GET)   
    47.     public String initForm(ModelMap model) {   
    48.         Account account = new Account();   
    49.         model.addAttribute("account", account);   
    50.         // 直接跳转到登录页面   
    51.         return "account/register";   
    52.     }   
    53.   
    54.     @RequestMapping(method = RequestMethod.POST)   
    55.     protected String submit(@ModelAttribute("account") Account account) {   
    56.         int id = accountService.register(account).getId();   
    57.         // 跳转到用户信息页面   
    58.         return "redirect:profile.do?id=" + id;   
    59.     }   
    60. }  
    1. /** 
    2.  * 2010-2-4 
    3.  */  
    4. package org.zlex.spring.controller;  
    5.   
    6. import java.text.DateFormat;  
    7. import java.text.SimpleDateFormat;  
    8. import java.util.Date;  
    9.   
    10. import org.springframework.beans.factory.annotation.Autowired;  
    11. import org.springframework.beans.propertyeditors.CustomDateEditor;  
    12. import org.springframework.stereotype.Controller;  
    13. import org.springframework.ui.ModelMap;  
    14. import org.springframework.web.bind.WebDataBinder;  
    15. import org.springframework.web.bind.annotation.InitBinder;  
    16. import org.springframework.web.bind.annotation.ModelAttribute;  
    17. import org.springframework.web.bind.annotation.RequestMapping;  
    18. import org.springframework.web.bind.annotation.RequestMethod;  
    19. import org.zlex.spring.domain.Account;  
    20. import org.zlex.spring.service.AccountService;  
    21.   
    22. /** 
    23.  * 用户注册控制器 
    24.  *  
    25.  * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a> 
    26.  * @version 1.0 
    27.  * @since 1.0 
    28.  */  
    29. @Controller  
    30. @RequestMapping(value = "/register.do")  
    31. public class RegisterController {  
    32.   
    33.     @Autowired  
    34.     private AccountService accountService;  
    35.   
    36.     @InitBinder  
    37.     public void initBinder(WebDataBinder binder) {  
    38.         // 忽略字段绑定异常  
    39.         // binder.setIgnoreInvalidFields(true);  
    40.   
    41.         DateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
    42.         binder.registerCustomEditor(Date.class, "birthday",  
    43.                 new CustomDateEditor(format, true));  
    44.     }  
    45.   
    46.     @RequestMapping(method = RequestMethod.GET)  
    47.     public String initForm(ModelMap model) {  
    48.         Account account = new Account();  
    49.         model.addAttribute("account", account);  
    50.         // 直接跳转到登录页面  
    51.         return "account/register";  
    52.     }  
    53.   
    54.     @RequestMapping(method = RequestMethod.POST)  
    55.     protected String submit(@ModelAttribute("account") Account account) {  
    56.         int id = accountService.register(account).getId();  
    57.         // 跳转到用户信息页面  
    58.         return "redirect:profile.do?id=" + id;  
    59.     }  
    60. }  


    @InitBinder用于表单自定义属性绑定。这里我们要求输入一个日期格式的生日。
    @RequestMapping(method = RequestMethod.GET)用于初始化页面。
    @RequestMapping(method = RequestMethod.POST)用于提交页面。
    再看注册页面
    register.jsp

    Jsp代码
    1. <html>   
    2. <head>   
    3. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">   
    4. <title>注册</title>   
    5. <link rel="stylesheet" type="text/css" href="css/style.css" />   
    6. <script type="text/javascript" src="js/calendar.js"></script>   
    7. </head>   
    8. <body>   
    9. <fieldset><legend>用户注册</legend><form:form   
    10.     commandName="account">   
    11.     <ul>   
    12.         <li><form:label path="username">用户名:</form:label><form:input   
    13.             path="username" /></li>   
    14.         <li><form:label path="password">密码:</form:label><form:password   
    15.             path="password" /></li>   
    16.         <li><form:label path="birthday">生日:</form:label><form:input   
    17.             path="birthday" onfocus="showDate(this);" /></li>   
    18.         <li><form:label path="email">Email:</form:label><form:input   
    19.             path="email" /></li>   
    20.         <li>   
    21.         <button type="submit">注册</button>   
    22.         <button type="reset">重置</button>   
    23.         </li>   
    24.     </ul>   
    25. </form:form></fieldset>   
    26. </body>   
    27. </html>  


    这里我用了一个JavaScript日期控制标签:

    Html代码
    1. <script type="text/javascript" src="js/calendar.js"></script>  
    1. <script type="text/javascript" src="js/calendar.js"></script>  


    使用起来就像是这样:

    非常好用!!! 当然,你完全可以使用JE上的那个JS控件!
    接下来稍微调整一下AccountService接口及其实现AccountServiceImpl
    AccountService.java

    Java代码
    1. public interface AccountService {   
    2.     // 省略   
    3.     /**  
    4.      * 注册用户  
    5.      *   
    6.      * @param account  
    7.      * @return  
    8.      */  
    9.     @Transactional(readOnly = false, rollbackFor = DataAccessException.class)   
    10.     Account register(Account account);   
    11.     // 省略   
    12. }  
    1. public interface AccountService {  
    2.     // 省略  
    3.     /** 
    4.      * 注册用户 
    5.      *  
    6.      * @param account 
    7.      * @return 
    8.      */  
    9.     @Transactional(readOnly = false, rollbackFor = DataAccessException.class)  
    10.     Account register(Account account);  
    11.     // 省略  
    12. }  
    Java代码
    1. @Service  
    2. public class AccountServiceImpl implements AccountService {   
    3.   
    4.     @Autowired  
    5.     private AccountDao accountDao;   
    6.   
    7.     // 省略   
    8.   
    9.     @Override  
    10.     public Account register(Account account) {   
    11.         accountDao.create(account);   
    12.         return accountDao.read(account.getUsername());   
    13.     }   
    14. }  
    1. @Service  
    2. public class AccountServiceImpl implements AccountService {  
    3.   
    4.     @Autowired  
    5.     private AccountDao accountDao;  
    6.   
    7.     // 省略  
    8.   
    9.     @Override  
    10.     public Account register(Account account) {  
    11.         accountDao.create(account);  
    12.         return accountDao.read(account.getUsername());  
    13.     }  
    14. }  


    为了在插入一条记录后获得当前用户的主键,我们还得这么玩! 的确有点雷人~
    从架构考虑,这是符合业务要求的实现!如果用iBatis或者Hibernate,这个问题就有数据库一次IO处理完成了!
    再看看AccountDao接口及其实现AccountDaoImpl
    AccountDao.java

    Java代码
    1. public interface AccountDao {   
    2.         // 省略   
    3.     /**  
    4.      * 构建用户记录  
    5.      *   
    6.      * @param account  
    7.      * @return  
    8.      */  
    9.     void create(Account account);   
    10. }  
    1. public interface AccountDao {  
    2.         // 省略  
    3.     /** 
    4.      * 构建用户记录 
    5.      *  
    6.      * @param account 
    7.      * @return 
    8.      */  
    9.     void create(Account account);  
    10. }  



    AccountDaoImpl.java

    Java代码
    1. @Repository  
    2. public class AccountDaoImpl implements AccountDao {   
    3.         // 省略   
    4.   
    5.     @Override  
    6.     public void create(Account account) {   
    7.         String sql = "INSERT INTO account(username, password, birthday, email) VALUES(?,?,?,?)";   
    8.   
    9.         jdbcTemplate.update(sql, new Object[] { account.getUsername(),   
    10.                 account.getPassword(), account.getBirthday(),   
    11.                 account.getEmail() });   
    12.     }   
    13. }  
    1. @Repository  
    2. public class AccountDaoImpl implements AccountDao {  
    3.         // 省略  
    4.   
    5.     @Override  
    6.     public void create(Account account) {  
    7.         String sql = "INSERT INTO account(username, password, birthday, email) VALUES(?,?,?,?)";  
    8.   
    9.         jdbcTemplate.update(sql, new Object[] { account.getUsername(),  
    10.                 account.getPassword(), account.getBirthday(),  
    11.                 account.getEmail() });  
    12.     }  
    13. }  


    来个注册演示!
    注册:

    信息展示:

    来制造一起事故!
    先看看数据库目前的状况!

    在AccountDaoImpl中来个破坏!

    Java代码
    1. @Override  
    2.     public void create(Account account) {   
    3.         String sql = "INSERT INTO account(username, password, birthday, email) VALUES(?,?,?,?)";   
    4.   
    5.         jdbcTemplate.update(sql, new Object[] { account.getUsername(),   
    6.                 account.getPassword(), account.getBirthday(),   
    7.                 account.getEmail() });   
    8.   
    9.         throw new RecoverableDataAccessException("TEST");   
    10.     }  
    1. @Override  
    2.     public void create(Account account) {  
    3.         String sql = "INSERT INTO account(username, password, birthday, email) VALUES(?,?,?,?)";  
    4.   
    5.         jdbcTemplate.update(sql, new Object[] { account.getUsername(),  
    6.                 account.getPassword(), account.getBirthday(),  
    7.                 account.getEmail() });  
    8.   
    9.         throw new RecoverableDataAccessException("TEST");  
    10.     }  


    我们强行在执行完Insert语句后抛出DataAccessException异常(RecoverableDataAccessException)!
    来个注册试试!

    点击提交看看返回的异常!

    异常回滚生效!
    数据库中当然是什么都没有,我就不废话了!

  • 相关阅读:
    poj 3280 Cheapest Palindrome(区间DP)
    POJ 2392 Space Elevator(多重背包)
    HDU 1285 定比赛名次(拓扑排序)
    HDU 2680 Choose the best route(最短路)
    hdu 2899 Strange fuction (三分)
    HDU 4540 威威猫系列故事――打地鼠(DP)
    HDU 3485 Count 101(递推)
    POJ 1315 Don't Get Rooked(dfs)
    脱离eclipse,手动写一个servlet
    解析xml,几种方式
  • 原文地址:https://www.cnblogs.com/Struggles/p/4368176.html
Copyright © 2020-2023  润新知