今日的三大主要內(nèi)容:Spring中的數(shù)據(jù)庫操作事務(wù)、Spring整合hibernate、Spring整合Struts1.X,最來再來一個SSH整合。
數(shù)據(jù)庫操作、數(shù)據(jù)庫事務(wù)管理、hibernate、Sturts,這些大家都已經(jīng)十分熟悉了。所以將他們與Spring整合使課程內(nèi)容比較簡單。Spring的特性是什么?不就是IOC的DI和AOP嗎!簡單在大腦里回顧一下,SSH整合正是使用這些特性。
一、Spring中的事務(wù)
Spring為什么提供對事務(wù)的支持?還記得我們在編寫OA項目時,為了統(tǒng)一處理一類事務(wù)的多個Dao方法對數(shù)據(jù)庫的操作是在一個事務(wù)中進行的,我們添加了一個“*.do”的過濾器,在過濾器中使用當(dāng)前線程(ThreadLocal)的Session來處理事務(wù)。
其中我們也曾提到過將事務(wù)統(tǒng)一在過濾器中只是為解決一時之需,將事務(wù)統(tǒng)一放在Service的方法中才是優(yōu)雅的做法。我們使用Spring就可以實現(xiàn)將事務(wù)統(tǒng)一放在Service的方法上。
1.在Spring中引入事務(wù)
通過外部Bean引入數(shù)據(jù)源我就不再做總結(jié)了,這里直接列出引入Spring中事務(wù)類的方法。下面為引入Jdbc的事務(wù)管理:
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
<tx:annotation-driven transaction-manager="transactionManager" /> |
“tx”元素指定使用注解進行事務(wù)處理的Bean。
引入Hibernate的事務(wù)管理:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> </bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
<tx:annotation-driven transaction-manager="transactionManager" /> |
2.使用Spring的事務(wù)
在Service方法上添加事務(wù)注解“@Transactional”,此時的Service方法便具有了事務(wù)管理。這正是使用AOP的編程思想,在過濾器上添加事務(wù)統(tǒng)一管理,也正是AOP的思想。
事務(wù)的傳播性,當(dāng)一個具有事務(wù)的方法調(diào)用另一個具有事務(wù)的方法時。此時可以設(shè)置事務(wù)的傳播屬性,實現(xiàn)不同的需求。事務(wù)的傳播性有:
傳播屬性 | 描述 |
REQUIRED | 如果有事務(wù)在運行,當(dāng)前的方法就在這個事務(wù)內(nèi)運行,否則啟動一個新的事務(wù),并在自己的事務(wù)內(nèi)運行。 |
REQUIRED_NEW | 當(dāng)前的方法必須啟動新的事務(wù),并在它自己的事務(wù)內(nèi)運行。如果有事務(wù)正在運行,則將它掛起。 |
SUPPORTS | 如果有事務(wù)在運行,當(dāng)前的方法就在這個事務(wù)內(nèi)運行。否則它可以不運行在事務(wù)中。 |
NOT_SUPPORTED | 當(dāng)前的方法 不運行在事務(wù)中。如果有運行的事務(wù),將它掛起。 |
MANDATORY | 當(dāng)前的方法運行在事務(wù)內(nèi)容,如果沒有正在運行的事務(wù),則拋異常。 |
NEVER | 當(dāng)前的方法不應(yīng)該運行在事務(wù)中。如果有運行的事務(wù),則拋異常。 |
NESTED | 如果有事務(wù)在運行,當(dāng)前的方法在這個事務(wù)的嵌套事務(wù)內(nèi)運行。否則,啟動一個新的事務(wù),并在它自己的事務(wù)內(nèi)運行。 |
前兩項是常用的。
“Transactional”注解所具有的屬性:
@Transactional(propagation=Propagation.REQUIRES_NEW, // 事務(wù)傳播屬性 isolation=Isolation.READ_COMMITTED,// 事務(wù)隔離級別 rollbackFor=Exception.class,// 異常回滾 unrollbackFor=IOException.class,// 異常不回滾 timeout=2, // 超時事務(wù) readOnly=false)// 只讀事務(wù) |
屬性 | 類型 | 描述 |
propagation | 枚舉型:Propagation | 可選的傳播性設(shè)置 |
isolation | 枚舉型:Isolation | 可選的隔離性級別(默認值:ISOLATION_DEFAULT) |
readOnly | 布爾型 | 讀寫型事務(wù) vs. 只讀型事務(wù)。只讀型事務(wù)一般用于查詢。 |
timeout | int型(以秒為單位) | 事務(wù)超時,如果在指定時間內(nèi)沒有完成事務(wù),事務(wù)則回滾。 |
rollbackFor | 一組 Class 類的實例,必須是Throwable 的子類 | 一組異常類,遇到時 必須 進行回滾。默認情況下checked exceptions不進行回滾,僅unchecked exceptions(即RuntimeException的子類)才進行事務(wù)回滾。 |
rollbackForClassname | 一組 Class 類的名字,必須是Throwable的子類 | 一組異常類名,遇到時 必須 進行回滾 |
noRollbackFor | 一組 Class 類的實例,必須是Throwable 的子類 | 一組異常類,遇到時 必須不 回滾。 |
noRollbackForClassname | 一組 Class 類的名字,必須是Throwable 的子類 | 一組異常類,遇到時 必須不 回滾 |
使用XML文件配置Spring事務(wù):
<tx:advice id="testTransaction" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="methodName" propagation="REQUIRED" read-only="false" rollback-for="Expetion" timeout="2" isolation="READ_COMMITTED" /> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut expression="execution(* cn.itcast.cc.spring.transaction.*.*(..))" id="aopTransaction" /> <aop:advisor advice-ref="testTransaction" pointcut-ref="aopTransaction" /> </aop:config> |
二、Spring整合Hibernate
Spring支持大多數(shù)流行的ORM框架,包括HibernateJDO,TopLink,Ibatis和JPA。它這些ORM框架的支持是一致的,因此可以把和Hibernate整合技術(shù)應(yīng)用到其他ORM框架上。Spring2.0同時支持Hibernate2.x和3.x。但Spring2.5只支持Hibernate3.1或更高版本
1.在Spring中配置SessionFactory
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> </bean> |
其中的DataSource是我們在第一天就講到的使用外部Bean配置數(shù)據(jù)源。
雖然我們使用的數(shù)據(jù)源是一個Bean,它涉及到Hibernate私有配置的信息被聲明在“hibernate.cfg.xml”文件中。但現(xiàn)在我們可以這個外在的“hibernate.cfg.xml”文件,我們需要在上面的baen中添加:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> <property name="mappingResources"> <list> <value>cn/itcast/spring/hibernate/Customer.hbm.xml</value> </list> </property> </bean> |
OK,SessionFactory已經(jīng)被我們整合進來了!十分簡單,跟其他的類一樣。
還記得我們昨天使用的JdbcTemplate嗎?那是Spring為JDBC提供的支持,Spring也有為Hibernate提供支持:
支持類 | JDBC | Hibernate |
模板類 | JdbcTemplate | HibernateTemplate |
DAO支持類 | JdbcDaoSupport | HibernateDaoSupport |
事務(wù)管理類 | DataSourceTransactionManager | HibernateTransactionManager |
使用HibernateTemplate,需要聲明一個Bean:
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"/> </bean>
|
DAO支持類對我們來說比較陌生,HibernateDAO可以通過繼承HibernateDaoSupport來繼承setSessionFactory()和setHibernateTemplate()方法。然后,只要在DAO方法中調(diào)用getHibernateTemplate()方法就可以獲取到模板實例。
三、Spring整合Struts1.x
1.通過注冊Servlet監(jiān)聽器ContextLoaderListener,Web應(yīng)用程序可以加載Spring的ApplicationContext對象。這個監(jiān)聽器會將加載好的ApplicationContext對象保存到Web應(yīng)用程序的ServletContext中。隨后,Servlet或可以訪問ServletContext的任意對象就能通過一個輔助方法來訪問Spring的應(yīng)用程序上下文了。
<context-param> <param-name>contextConfigFile</param-name> <param-value>beans.xml</param-value> </context-param> <listener> <listener-class>cn.itcast.cc.spring.SpringServletContextListener</listener-class> </listener> |
在SpringServletContextListener的contextInitialized方法中:
public void contextInitialized(ServletContextEvent arg0) { String cfgFile = arg0.getServletContext().getInitParameter("contextConfigFile"); ApplicationContext ac = new ClassPathXmlApplicationContext(cfgFile); arg0.getServletContext().setAttribute("applicationContext", ac); } |
以后在Action中需要使用SpringIOC容器中的Bean時,就可以先到ServletContext中去獲取ApplicationContext,然后再獲取相應(yīng)的Bean。
2.在web.xml文件中注冊Spring提供的Servlet監(jiān)聽器ContextLoaderListener,它會在當(dāng)前web應(yīng)用被加載時將Spring的ApplicationContext保存到ServletContext對象中。
ContextLoaderListener監(jiān)聽器通過查找web應(yīng)用初始化參數(shù)contextConfigLocation來獲取Bean配置文件的位置。如果有多個Bean配置文件,可以通過逗號或空格進行分隔。contextConfigLocation的默認值為/WEB-INF/applicationContext.xml。若實際的文件和默認值一致則可以省略這個web應(yīng)用的初始化參數(shù)。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> |
在需要Bean的Action或Servlet中獲取Bean的方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext()); ac.getBean("beanName"); } |
3.通過注冊Servlet監(jiān)聽器ContextLoaderListener,Struts應(yīng)用程序能夠加載Spring的ApplicationContext對象,并像在通用的Web應(yīng)用程序中那樣在Servlet上下文中對它進行訪問。然而,Spring還提供了更好的,特定于Struts的解決方案。
-
在struts配置文件中注冊Struts插件來加載應(yīng)用程序上下文,它會自動引用Servlet監(jiān)聽器加載的應(yīng)用程序上下文作為它的父上下文,以便可以引用其中聲明的Bean。
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="classpath:struts-config.xml,classpath:beans.xml" /> </plug-in> |
Spring提供了一個ActionSupport對象,這是Action類的一個子類,通過它的getWebApplicationContext()方法可以獲取到Spring的應(yīng)用程序上下文。
public class LoginAction extends ActionSupport {
@Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ApplicationContext ac = this.getWebApplicationContext(); HelloSpring hs = (HelloSpring) ac.getBean("helloSpring"); request.setAttribute("message", hs.hello("changcheng")); return mapping.findForward("success"); } } |
-
在spring的應(yīng)用程序上下文中聲明Struts的Action對象,使用Spring的依賴注入來注入Spring應(yīng)用程序上下文的其他Bean。
我們的Action類:
public class LoginAction extends Action { private HelloSpring helloSpring; public void setHelloSpring(HelloSpring hs) { this.helloSpring = hs; System.out.println("*****注入*****:" + this.helloSpring); }
@Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { request.setAttribute("message", this.helloSpring.hello("changcheng")); return mapping.findForward("success"); } } |
在struts-config.xml中將的Action配置為:
<action-mappings> <action path="/login"> <forward name="success" path="/success.jsp" /> </action> </action-mappings>
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor" /> |
在beans.xml中配置:
<bean id="helloSpring" class="cn.itcast.cc.spring.struts.hello.HelloSpring" /> <bean name="/login" class="cn.itcast.cc.spring.struts.action.LoginAction"> <property name="helloSpring" ref="helloSpring"/> </bean> |
這種方法也需要“1)”的plug-in。
四、SSH整合(Spring、Struts1.x、Hibernate)
將上面的二和三放到一起就是SSH整合,佟老師使用一個使用注冊的例子演示SSH整合。我只簡單說一下思想吧!
1).創(chuàng)建動態(tài)WEB工程。
2).在web.xml添加spring的“ContextLoaderListener”監(jiān)聽器和Struts的ActionServlet。
3).在Spring的配置文件中引入數(shù)據(jù)源和Hibernate的SessionFactory和HibernateTransactionManager。
4).為struts添加spring的“DelegatingRequestProcessor”控制器。
5).為Action、Service、Dao添加Spring的AOP注解。
Spring結(jié)束了就是教育辦公系統(tǒng)了,這個十分重要,要好好學(xué)習(xí)!