熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

spring是如何對Service進行事務管理的

2013-11-23 20:23:47  來源: Java開源技術 

  本人也很想弄清楚spring是如何對Service進行事務管理的並且還去看了一下spring框架關於事務管理幾個相關類的源碼可惜由於本人功力有限只看懂了皮毛.

  既然源代碼看不懂那麼只有運用例子進行測試雖然笨了點不過管是白貓還是黑貓能捉老鼠就是好貓.

  為引起不必要的爭論本帖子只針對本案例的測試結果進行小結並保證此測試代碼在本人的運行環境絕對正確.

  開發環境

  OSwindows Server

  Web Server: jakartatomcat

  DataBase Server: MS SQL Server (打了SP3補丁)

  IDE: Eclipse +MyEclipse GA

  測試案例系統結構

  web層<>Service層<>DAO層

  web層使用struts DAO使用的spring的JDBCspring版本

  數據庫中有兩張表

  student和Student表結構相同idnameaddress.其中id為主鍵且為自增長型

  student表中有一條記錄

  id  name       address

     xiaoming    wuhan

  student表中記錄為空

  測試情形一

  web層捕獲異常並處理DAO層不捕獲異常Service也不捕獲異常.

  Service層接口

  public interface StudentManagerService {

  public void  bus_method();

  }

  DAO層接口

  public interface StudentDAO {

  public void  deleteStudent();

  public void  insertStudent();

  }

  StudentDAO接口的實現

  public class StudentDAOImp extends JdbcDaoSupport implements StudentDAO{

  //刪除student表中的id=的記錄

  public void  deleteStudent(){

  JdbcTemplate jt=thisgetJdbcTemplate();

  jtupdate(delete from student where id=);

  }

  //將student表中刪除的記錄插入到student但是此方法實現有錯因為

  //id字段設置為自增長的所以在插入記錄時我們不能指定值

  public void  insertStudent(){

  JdbcTemplate jt=thisgetJdbcTemplate();

  String arg[]=new String[];

  arg[]=;

  arg[]=xiaoming;

  arg[]=wuhan;

  jtupdate(insert student(idnameaddress) values(???)arg);

  }

  }

  StudentManagerService 接口的實現

  public class StudentManagerServiceImp implements StudentManagerService{

  private StudentDAO  stdDAO;

  public void setStdDAO(StudentDAO   stdDAO){

  thisstdDAO=stdDAO;

  }

  //此方法為事務型的刪除student中的記錄成功且插入student的記錄也成功

  //如果insertStudent()方法執行失敗那麼deleteStudent()方法也應該會失敗

  public void  bus_method(){

  thisstdDAOdeleteStudent();

  thisstdDAOinsertStudent();

  }

  }

  web層:

  三個jsp一個action:

  indexjsp ==>首頁面.上面僅僅有一個超鏈接<a herf=testdo>執行</a>

  chenggongjsp ==>Service執行成功後轉向的JSP頁面

  shibaijsp ====>Service執行失敗後轉向的JSP頁面

  action實現

  public class StudentManagerAction  extends  Action{

  public ActionForward execute(ActionMapping mapping ActionForm form

  HttpServletRequest request HttpServletResponse response) {

  try{

  WebApplicationContext appContext=WebApplicationContextUtils

  getWebApplicationContext(thisgetServlet()getServletContext());

  StudentManagerService stdm=(StudentManagerService)appContext

  getBean(stdServiceManager);

  stdmbus_method();

  return mappingfindForward(chenggong);

  }

  catch(DataAccessException e){

  Systemerrprintln(action execute service exception!);

  return mappingfindForward(shibai);

  }

  }

  }

  配置文件

  webxml

  <?xml version= encoding=UTF?>

  <webapp xmlns= xmlns:xsi=instance version= xsi:schemaLocation=app__xsd>

  <contextparam>

  <paramname>logjConfigLocation</paramname>

  <paramvalue>/WEBINF/logjproperties</paramvalue>

  </contextparam>

  <contextparam>

  <paramname>contextConfigLocation</paramname>

  <paramvalue>/WEBINF/applicationContextxml</paramvalue>

  </contextparam>

  <listener>

  <listenerclass>orgspringframeworkwebutilLogjConfigListener</listenerclass>

  </listener>

  <listener>

  <listenerclass>orgsprntextContextLoaderListener</listenerclass>

  </listener>

  <servlet>

  <servletname>action</servletname>

  <servletclass>orgapachestrutsactionActionServlet</servletclass>

  <initparam>

  <paramname>config</paramname>

  <paramvalue>/WEBINF/strutsconfigxml</paramvalue>

  </initparam>

  <initparam>

  <paramname>debug</paramname>

  <paramvalue></paramvalue>

  </initparam>

  <initparam>

  <paramname>detail</paramname>

  <paramvalue></paramvalue>

  </initparam>

  <loadonstartup></loadonstartup>

  </servlet>

  <servletmapping>

  <servletname>action</servletname>

  <urlpattern>*do</urlpattern>

  </servletmapping>

  </webapp>

  sturtsconfigxml

  <strutsconfig>

  <actionmappings >

  <action  input=/indexjsp  path=/test  type=testStudentManagerAction   >

  <forward name=chenggong path=/chenggongjsp />

  <forward name=shibai path=/shibaijsp />

  </action>

  </actionmappings>

  <messageresources parameter=testApplicationResources />

  </strutsconfig>

  applicationContextxml

  <?xml version= encoding=UTF?>

  <!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN beansdtd>

  <beans>

  <bean id=dataSource

  class=monsdbcpBasicDataSource destroymethod=close >

  <property name=driverClassName value=commicrosoftjdbcsqlserverSQLServerDriver></property>

  <property name=url value=jdbc:microsoft:sqlserver://:;databasename=test></property>

  <property name=username value=sa></property>

  <property name=password value=sa></property>

  </bean>

  <bean id=transactionManager class=orgspringframeworkjdbcdatasourceDataSourceTransactionManager>

  <property name=dataSource ref=dataSource/>

  </bean>

  <bean id=baseTxProxy class=orgspringframeworktransactioninterceptorTransactionProxyFactoryBean  lazyinit=true>

  <property name=transactionManager>

  <ref bean=transactionManager />

  </property>

  <property name=transactionAttributes>

  <props>

  <prop key=*>PROPAGATION_REQUIRED</prop>

  </props>

  </property>

  </bean>

  <bean id=stdServiceManager  parent=baseTxProxy >

  <property name=target>

  <bean class=testStudentManagerServiceImp>

  <property name=stdDAO>

  <ref bean=stdDAO/>

  </property>

  </bean>

  </property>

  </bean>

  <bean id=stdDAO class=testStudentDAOImp>

  <property name=dataSource ref=dataSource/>

  </bean>

  </beans>

  運行程序啟動服務器並部署.進入indexjsp頁面點擊執行超鏈接>頁面跳向shibaijsp

  查看控制台打印有action execute service exception!

  查看數據庫 student表中的[ xiaoming wuhan] 記錄仍然存在student表仍然為空.

  小結如果DAO層和Service不捕獲異常而在web層捕獲異常web成功捕獲異常spring事務管理成功!

  測試情形二

  web層捕獲異常並處理Service捕獲異常並處理DAO層不捕獲異常.

  修改StudentManagerServiceImp類

  public class StudentManagerServiceImp implements StudentManagerService{

  private StudentDAO  stdDAO;

  public void setStdDAO(StudentDAO   stdDAO){

  thisstdDAO=stdDAO;

  }

  //此方法為事務型的刪除student中的記錄成功且插入student的記錄也成功

  //如果insertStudent()方法執行失敗那麼deleteStudent()也應該會失敗

  public void  bus_method(){

  try{

  thisstdDAOdeleteStudent();

  thisstdDAOinsertStudent();

  }

  catch(DataAccessException de)

  Systemerrprintln(service execute exception!);

  }

  }

  }

  運行程序啟動服務器並部署.進入indexjsp頁面點擊執行超鏈接>頁面跳向chenggongjsp

  查看控制台打印有service execute exception!

  查看數據庫 student表中的[ xiaoming wuhan] 記錄不存在student表仍然為空.

  小結如果Service捕獲異常並處理而不向外拋出web層捕獲不到異常spring事務管理失敗!

  測試情形(還原表中的數據)三

  web層捕獲異常Service捕獲異常DAO層也捕獲異常.

  修改StudentDAOImp類代碼

  public class StudentDAOImp extends JdbcDaoSupport implements StudentDAO{

  //刪除student表中的id=的記錄

  public void  deleteStudent(){

  try{

  JdbcTemplate jt=thisgetJdbcTemplate();

  jtupdate(delete from student where id=);

  }

  catch(DataAccessException e){

  Systemerrprintln(dao deleteStudent execute exception!);

  }

  }

  //將student表中刪除的記錄插入到student但是此方法實現有錯因為

  //id字段設置為自增長的所以在插入記錄時我們不能指定值

  public void  insertStudent(){

  try{

  JdbcTemplate jt=thisgetJdbcTemplate();

  String arg[]=new String[];

  arg[]=;

  arg[]=xiaoming;

  arg[]=wuhan;

  jtupdate(insert student(idnameaddress) values(???)arg);

  }

  catch(DataAccessException  e){

  Systemerrprintln(dao insertStudent  execute exception!);

  }

  }

  }

  運行程序啟動服務器並部署.進入indexjsp頁面點擊執行超鏈接>頁面跳向chenggongjsp

  查看控制台打印有dao insertStudent execute exception!

  查看數據庫 student表中的 xiaomingwuhan 記錄不存在student表仍然為空.

  小結如果DAO的每一個方法自己捕獲異常並處理而不向外拋出Service層捕獲不到異常Web層同樣捕獲不到異常spring事務管理失敗!

  測試情形四

  還原數據庫中的數據

  還原StudentDAOImp類中的方法為測試情形一中的實現

  web層捕獲異常Service拋出的自定義異常StudentManagerException

  Service捕獲DataAccessException並拋出StudentManagerException

  StudentManagerException為DataAccessException的子類

  DAO層不捕獲異常

  修改StudentManagerServiceImp類的實現

  public class StudentManagerServiceImp implements StudentManagerService{

  private StudentDAO  stdDAO;

  public void setStdDAO(StudentDAO   stdDAO){

  thisstdDAO=stdDAO;

  }

  //此方法為事務型的刪除student中的記錄成功且插入student的記錄也成功

  //如果insertStudent()方法執行失敗那麼deleteStudent()也應該會失敗

  public void  bus_method() throws StudentManagerException{

  try{

  thisstdDAOdeleteStudent();

  thisstdDAOinsertStudent();

  }

  catch(DataAccessException de)

  Systemerrprintln(service execute exception!);

  throw new StudentManagerException();//StudentManagerException類繼承DataAcce                          //ssException異常

  }

  }

  }

  修改StudentManagerAction

  public class StudentManagerAction  extends  Action{

  public ActionForward execute(ActionMapping mapping ActionForm form

  HttpServletRequest request HttpServletResponse response) {

  try{

  WebApplicationContext appContext=WebApplicationContextUtils

  getWebApplicationContext(thisgetServlet()getServletContext());

  StudentManagerService stdm=(StudentManagerService)appContext

  getBean(stdServiceManager);

  stdmbus_method();

  return mappingfindForward(chenggong);

  }

  catch(StudentManagerException e){

  Systemerrprintln(action execute service exception!);

  return mappingfindForward(shibai);

  }

  }

  }

  運行程序啟動服務器並部署.進入indexjsp頁面點擊執行超鏈接>頁面跳向shibaijsp

  查看控制台打印有service execute exception!

  action execute service exception!

  查看數據庫 student表中的 [xiaomingwuhan] 記錄仍然存在student表仍然為空.

  小結如果DAO的每一個方法不捕獲異常Service層捕獲DataAccessException異常並拋出自己定義異常(自定義異常為DataAccessException的子類)Web層可以捕獲到異常spring事務管理成功!

  結合源碼總結

  spring在進行聲明時事務管理時通過捕獲Service層方法的DataAccessException來提交和回滾事務的而Service層方法的DataAccessException又是來自調用DAO層方法所產生的異常.

  我們一般在寫DAO層代碼時如果繼承JdbcDaoSupport 類並使用此類所實現的JdbcTemplate來執行數據庫操作此類會自動把低層的SQLException轉化成DataAccessException以及DataAccessException

  的子類.

  一般在Service層我們可以自己捕獲DAO方法所產成的DataAccessException然後再拋出一個業務方法有意義的異常(ps:此異常最好繼承DataAccessException)然後在Web層捕獲這樣我們就可以手動編碼的靈活實現通過業務方法執行的成功和失敗來向用戶轉發不同的頁面.


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28430.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.