SSH三框架的整合开发问题

来源:互联网 发布:妖王爬床免费阅读软件 编辑:程序博客网 时间:2024/06/05 18:19
给你详细讲一下SSH框架的事物管理,希望对你有帮助。Struts+hibernate+spring整合开发web应用是相当流行的,只需要简单的配置就能轻松的对数据库进行crud操作,下面就hibernate+spring的配置做一下剖析,一边与大家一起分享经验:1、  准备工作:可以利用hibernate tools生成相关映射文件已经po对象、dao对象,dao也可以自己手动编写,无非就是实现crud,如果通过继承hibernate提供的HibernateDaoSupport,则可以更轻松的实现关键就在于配置文件,下面看一个样例app.xml:<?xml version="1.0" encoding="utf-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置数据源--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">       <!-- 指定连接数据库的驱动 -->       <property name="driverClass" value="com.mysql.jdbc.Driver"/>       <!-- 指定连接数据库的URL -->       <property name="jdbcUrl" value="jdbc:mysql://localhost/auction"/>       <!-- 指定连接数据库的用户名 -->       <property name="user" value="root"/>       <!-- 指定连接数据库的密码 -->       <property name="password" value="root"/>       <!-- 指定连接数据库连接池的最大连接数 -->       <property name="maxPoolSize" value="20"/>       <!-- 指定连接数据库连接池的最小连接数 -->       <property name="minPoolSize" value="1"/>       <!-- 指定连接数据库连接池的初始化连接数 -->       <property name="initialPoolSize" value="1"/>       <!-- 指定连接数据库连接池的连接的最大空闲时间 -->       <property name="maxIdleTime" value="20"/>    </bean>       <!--配置数据库会话工厂-->    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">       <property name="dataSource" ref="dataSource"/>       <property name="mappingResources">           <list>              <value>com/ouya/User.hbm.xml</value>           </list>       </property>        <property name="hibernateProperties">    <props>     <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>     <prop key="hibernate.show_sql">true</prop>     <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>    </props>   </property>     </bean> <!--配置事务管理器--><bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">   <property name="sessionFactory"><ref local="sessionFactory"/></property></bean>    <!—-配置Spring 事务管理器代理 --><bean id="transactionProxyFactory" abstract="true" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">    <property name="transactionManager">         <ref local="transactionManager"/>    </property>    <property name="transactionAttributes">         <props>          <prop key="save*">PROPAGATION_REQUIRED</prop>           <prop key="insert*">PROPAGATION_REQUIRED</prop>           <prop key="del*">PROPAGATION_REQUIRED</prop>           <prop key="add*">PROPAGATION_REQUIRED</prop>           <prop key="update*">PROPAGATION_REQUIRED</prop>           <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="remove*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="count*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>    </props>   </property>    </bean>    <!-- Hibernate模板 --><bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">   <property name="sessionFactory">    <ref local="sessionFactory" />   </property></bean>    <!--服务层对象-->    <bean id="us" class="com.ouya.UserService">     <property name="userDao">      <ref local="userDao"/>     </property>    </bean>    <!-- spring代理用户服务对象 --><bean id="userService" parent="transactionProxyFactory"><!-- 如果上面的服务层对象实现了接口,则此处必须设置proxyTargetClass为true,否则会报classcast异常 --><!--<property name="proxyTargetClass" value="true"/>-->       <property name="target" ref="us"/></bean>    <!-- 用户数据访问对象DATA ACCESS OBJECT --><bean id="userDao" class="com.ouya.UserDAO">   <property name="hibernateTemplate" ref="hibernateTemplate"/></bean>    </beans>可以看到配置文件的步骤:1、  配置数据源2、  配置会话工厂(依赖注入上面的数据源,还要注入hbm映射文件[注意正确的位置]、hibernate属性文件)3、  配置事务管理器(依赖注入上面的会话工厂)4、  Spring中声明事务管理器(根据需要又可分为几种,但都要依赖注入上面的事务管理器,此外还需要配置transationAttributes)后面的一些普通的bean配置就不用说了上面的例子中使用的声明事务管理器是:TransactionProxyFactoryBean,这样的话我们就需要在后面配置目标bean,比如上面的例子中我们的原服务对象是id为us的UserService(没有实现接口),所以我们为他配置了id为userService的代理对象(目标bean),程序中使用时只能通过使用代理对象才能实现数据库操作功能(代理对象的父类是上面声明的事务管理器,一边我们使用的时候开启事务),如果直接使用服务对象就无法开启事务程序中调用:UserService us = (UserService) app.getBean("userService");注:userService就是上面配置的代理对象的id,而不是原服务对象的id 但是如果我们想通过原服务对象的id来使用对象,则我们需要使用代理事务管理器BeanNameAutoProxyCreator(根据beanname自动代理),上面的配置文件需要做改动,做两件事(当然先要删除原来配置的TransactionProxyFactoryBean,不然就混乱了,可能会报错的):1、  增加一个事务拦截器<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">    <property name="transactionManager">         <ref local="transactionManager"/>    </property>    <property name="transactionAttributes">         <props>          <prop key="save*">PROPAGATION_REQUIRED</prop>           <prop key="insert*">PROPAGATION_REQUIRED</prop>           <prop key="del*">PROPAGATION_REQUIRED</prop>           <prop key="add*">PROPAGATION_REQUIRED</prop>           <prop key="update*">PROPAGATION_REQUIRED</prop>           <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="remove*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="count*">PROPAGATION_REQUIRED,readOnly</prop>           <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>    </props>   </property></bean>2、  定义自动代理事务管理器<!-- 定义BeanNameAutoProxyCreator--><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><!--  如果服务层对象是接口实现类,则需要设置proxyTargetClass属性为true --><!--<property name="proxyTargetClass" value="true"-->        <!--  指定对满足哪些bean name的bean自动生成业务代理 -->        <property name="beanNames">            <!--  下面是所有需要自动创建事务代理的bean-->            <list>                <value>us</value>            </list>            <!--  此处可增加其他需要自动创建事务代理的bean-->        </property>        <!--  下面定义BeanNameAutoProxyCreator所需的事务拦截器-->        <property name="interceptorNames">            <list>                <!-- 此处可增加其他新的Interceptor -->                <value>transactionInterceptor</value>            </list>        </property></bean>然后我们在程序中调用时应如下:UserService us = (UserService) app.getBean("us");注:注意与上面使用TransactionProxyFactoryBean时的调用区别,此处我们用getbean时直接取原服务层对象的id,不需要去配置目标bea,这也正是BeanNameAutoProxyCreator(根据bean名称自动代理)的含义所在    附录:1、关于hibernate的属性详解:<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><!-- 以下配置都是使用 jdbc.properties 属性文件中的配置,而之所以可以这样写,就是因为有 属性占位符配置的原因 --><property name="driverClass" value="${jdbc.driverClassName}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><!-- 连接池维持的最小的连接个数 --><property name="minPoolSize" value="5"/><!-- 连接池维持的最大的连接个数 --><property name="maxPoolSize" value="20"/><!-- 最大空闲时间, 当某个连接在这个时间内没活动后将从池中移除,前提是池中至少多于最少的连接数: minPoolSize --><property name="maxIdleTime" value="1800"/><!-- 为加强准备语句的执行性能,此参数指定被缓存的 PreparedStatement 的个数 --><property name="maxStatements" value="50"/></bean> Hibernate 会话厂 SessionFactorySession 就是用于每次与数据库会话的,因此需要:数据库的配置参数,这些参数就是 上面的数据源指定的! 因此我们只需引用即可: ref="dataSource";实体映射配置 hibernate.cfg.xml 配置结果缓存配置(这里使用的是开源的 ehcache) <!-- Hibernate SessionFactory --><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><!-- 引用前面定义的数据源 --><property name="dataSource" ref="dataSource"/><!-- 所有实体映射文件列表, 所有的 hbm.xml 文件 --><property name="mappingResources"><list><value>org/springframework/samples/jpetstore/domain/Account.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Banner.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Category.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Inventory.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Item.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/LineItem.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Order.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Product.hbm.xml</value><value>org/springframework/samples/jpetstore/domain/Supplier.hbm.xml</value></list></property><!-- 传统上的 hibernate.cfg.xml 文件的参数放在这里 --><property name="hibernateProperties"><props><!-- 指定数据库方言 --><prop key="hibernate.dialect">${hibernate.dialect}</prop><!-- 是否在日志中输出所有Hibernate与数据库交互的SQL语句 --><prop key="hibernate.show_sql">true</prop><!-- 是否在日志中输出的SQL 语句格式化成易读形式 --><prop key="hibernate.format_sql">true</prop><!-- 是否显示统计形式,一般在测试阶段使用 --><prop key="hibernate.generate_statistics">true</prop><!-- 对于级联查询,一次性获取的级联深度, @todo 需进一步研究 --><prop key="hibernate.max_fetch_depth">2</prop><!--Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数,一般设置为30、50、100。Oracle数据库的JDBC驱动默认的Fetch Size=15,设置Fetch Size设置为:30、50,性能会有明显提升,如果继续增大,超出100,性能提升不明显,反而会消耗内存。--><prop key="hibernate.jdbc.fatch_size">100</prop><!--不必等到累计到50个SQL之后才执行.只要事务commit后,不管缓存中有多少条sql语句都要执行.hibernate.jdbc.batch_size参数只是设定一次最多可以提交多少sql语句的上限,提高sql语句的执行效率--><prop key="hibernate.jdbc.batch_size">50</prop><!--(1)create 在每次SesstionFactory 构建时(一般是应用重启时,或者伴随着应用服务器重启时),先将之前数据库中的所有数据全部清空,后紧跟着根据所有的hbm.xml 映射文件重新创建新的数据库表 (2)create-drop 除了create 的所有含义之外,在每次应用的退出前,将进行一次数据空清空。因此这个配置将有两次清空操作,一次是退出,一次是启动时。 (3)update如果在开发阶段理发了实体对象的映射文件(hbm.xml) 的定义后,此配置将后台的数据库表进行更新(如增加表的列) (4)validate用于校验现有的表与现有的配置是否一致。--><prop key="hibernate.hbm2ddl.auto">update</prop><!-- 见下面的解释 --><prop key="hibernate.hbm2ddl.auto">update</prop><!--结果缓存配置:- 将ehcache.xml 置于 classpath 中- 如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、 list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置hibernate.cache.use_query_cache true 才行- 在Hbm文件中添加<cache usage="read-only"/>-如果需要“查询缓存”,还需要在使用Query或Criteria()时设置其setCacheable(true);属性--><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop></props></property><!-- 为解决 merge()方法语义的歧义 @todo 以后进一步解析或者你可以看一下相应的文档 --><property name="eventListeners"><map><entry key="merge"><bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/></entry></map></property></bean> 2、Spring的transactionAttributes PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。