一、 Spring 中的事务
Spring 为什么提供对事务的支持?还记得我们在编写 OA 项目时,为了统一处理一类事务的多个 Dao 方法对数据库的操作是在一个事务中进行的,我们添加了一个“ *.do” 的过滤器,在过滤器中使用当前线程( ThreadLocal )的 Session 来处理事务。
其中我们也曾提到过将事务统一在过滤器中只是为解决一时之需,将事务统一放在 Service 的方法中才是优雅的做法。我们使用 Spring 就可以实现将事务统一放在 Service 的方法上。
1. 在 Spring 中引入事务
通过外部 Bean 引入数据源我就不再做总结了,这里直接列出引入 Spring 中事务类的方法。下面为引入 Jdbc 的事务管理:
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
“tx” 元素指定使用注解进行事务处理的 Bean 。
引入 Hibernate 的事务管理:
<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 的事务
在 Service 方法上添加事务注解“ @Transactional ” ,此时的 Service 方法便具有了事务管理。这正是使用 AOP 的编程思想,在过滤器上添加事务统一管理,也正是 AOP 的思想。
事务的传播性,当一个具有 事务的方法调用另一个具有事务的方法时。此时可以设置事务的传播属性,实现不同的需求。事务的传播性有:
传播属性 | 描 述 |
REQUIRED | 如 果有事务在运行,当前的方法就在这个事务内运行,否则启动一个新的事务,并在自己的事务内运行。 |
REQUIRED_NEW | 当前的方法必须启动新的事务,并在它自己的事务内运行。如果有事务正在运行,则将它挂起。 |
SUPPORTS | 如果有事务在运行,当前的 方法就在这个事务内运行。否则它可以不运行在事务中。 |
NOT_SUPPORTED | 当前的方法 不运行在事务中。如果有运行的事务,将它挂起。 |
MANDATORY | 当前的方法运行在事务内容,如果没有 正在运行的事务,则抛异常。 |
NEVER | 当前的方法不应该运行在事 务中。如果有运行的事务,则抛异常。 |
NESTED | 如果有事务在运行,当前的方法在这个事务的嵌套事务内运行。否则,启动一个新的事 务,并在它自己的事务内运行。 |
前两项是常用的。
“Transactional ” 注解所具有的属性:
@Transactional(propagation=Propagation.REQUIRES_NEW, // 事务传播属性
isolation=Isolation.READ_COMMITTED,// 事务隔离级别
rollbackFor=Exception.class,// 异常回滚
unrollbackFor=IOException.class,// 异常不回滚
timeout=2, // 超时事务
readOnly=false)// 只读事务
属性 | 类型 | 描述 |
propagation | 枚举型: Propagation | 可选的传播性设置 |
isolation | 枚举型: Isolation | 可选的隔离性级别(默认值: ISOLATION_DEFAULT ) |
readOnly | 布尔型 | 读写型事务 vs. 只读型事务。只读型事务一般用于查询。 |
timeout | int 型(以秒为单位) | 事务超时,如果在指定时间内没有完成 事务,事务则回滚。 |
rollbackFor | 一组 Class 类的实例,必须是 Throwable 的子类 | 一组异常类,遇到时 必须 进行回滚。默认情况下 checked exceptions 不进行回滚,仅 unchecked exceptions (即 RuntimeException 的子类)才进行事务回滚。 |
rollbackForClassname | 一组 Class 类的名字,必须是 Throwable 的子类 | 一组异常类名,遇到时 必须 进行回滚 |
noRollbackFor | 一组 Class 类的实例,必须是 Throwable 的子类 | 一组异常类,遇到时 必须不 回滚。 |
noRollbackForClassname | 一组 Class 类的名字,必须是 Throwable 的子类 | 一组异常类,遇到时 必须不 回滚 |
使用 XML 文件配置 Spring 事务:
<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 支持大多数流行的 ORM 框架,包括 HibernateJDO , TopLink , Ibatis 和 JPA 。它这些 ORM 框架的支持是一致的,因此可以把和 Hibernate 整合技术应用到其他 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 配置数据源。
虽然我们使用的数据源是一个 Bean ,它涉及到 Hibernate 私有配置的信息被声明在“ hibernate.cfg.xml” 文件中。但现在我们可以这个外在的“ 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 已经被我们整合进来了!十分简单,跟其他的类一样。
还记得我们昨天使用的 JdbcTemplate 吗?那是 Spring 为 JDBC 提供的支持, Spring 也有为 Hibernate 提供支持:
支持类 | JDBC | Hibernate |
模板类 | JdbcTemplate | HibernateTemplate |
DAO 支持类 | JdbcDaoSupport | HibernateDaoSupport |
事务管理类 | 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 方法中调用 getHibernateTemplate() 方法就可以获取到模板实例。
三、 Spring 整 合 Struts1.x
1 . 通过注册 Servlet 监听器 ContextLoaderListener , Web 应用程序可以加载 Spring 的 ApplicationContext 对象。这个监听器会将加载好的 ApplicationContext 对象保存到 Web 应用程序的 ServletContext 中。随后, Servlet 或可以访问 ServletContext 的任意对象就能通过一个辅助方法来访问 Spring 的应用程序上下文了。
<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 ,然后再获取相应的 Bean 。
2 . 在 web.xml 文件中注册 Spring 提供的 Servlet 监听器 ContextLoaderListener ,它会在当前 web 应用被加载时将 Spring 的 ApplicationContext 保存到 ServletContext 对象中。
ContextLoaderListener 监听器通过查找 web 应用初始化参数 contextConfigLocation 来获取 Bean 配置文件的位置。如果有多个 Bean 配置文件,可以通过逗号或空格进行分隔。 contextConfigLocation 的默认值为 /WEB-INF/applicationContext.xml 。若实际的文件和默认值一致则可以省略这个 web 应用的初始化参数。
<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 监听器 ContextLoaderListener , Struts 应用程序能够加载 Spring 的 ApplicationContext 对象,并像在通用的 Web 应用程序中那样在 Servlet 上下文中对它进行访问。然而, Spring 还提供了更好的,特定于 Struts 的解决方案。
-
在 struts 配置文件中注册 Struts 插件来加载应用程序上下文,它会自动引用 Servlet 监听器加载的应用程序上下文作为它的父上下文,以便可以引用其中声明的 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 的应用程序上下文。
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 的应用程序上下文中声明 Struts 的 Action 对象,使用 Spring 的依赖注入来注入 Spring 应用程序上下文的其他 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). 创建动态 WEB 工程。
2). 在 web.xml 添加 spring 的“ ContextLoaderListener ” 监听器和 Struts 的 ActionServlet 。
3). 在 Spring 的配置文件中引入数据源和 Hibernate 的 SessionFactory 和 HibernateTransactionManager 。
4). 为 struts 添加 spring 的“ DelegatingRequestProcessor ” 控 制器。
5). 为 Action 、 Service 、 Dao 添加 Spring 的 AOP 注解。