`
happehope
  • 浏览: 1501 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Java 面试经典指南(2)

阅读更多
Java 面试经典指南(2)
Spring事务配置的五种方式
    前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较好掌握的。
    总结如下:
    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。
    DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
    具体如下图:

    根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:
    第一种方式:每个Bean都有一个代理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory" 
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean> 

    <!-- 定义事务管理器(声明式的事务) --> 
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
    <!-- 配置DAO -->
    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
    <bean id="userDao" 
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
           <!-- 配置事务管理器 --> 
           <property name="transactionManager" ref="transactionManager" />    
        <property name="target" ref="userDaoTarget" /> 
         <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
        <!-- 配置事务属性 --> 
        <property name="transactionAttributes"> 
            <props> 
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props> 
        </property> 
    </bean> 
</beans>
    第二种方式:所有Bean共享一个代理基类
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory" 
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean> 

    <!-- 定义事务管理器(声明式的事务) --> 
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
    <bean id="transactionBase" 
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
            lazy-init="true" abstract="true"> 
        <!-- 配置事务管理器 --> 
        <property name="transactionManager" ref="transactionManager" /> 
        <!-- 配置事务属性 --> 
        <property name="transactionAttributes"> 
            <props> 
                <prop key="*">PROPAGATION_REQUIRED</prop> 
            </props> 
        </property> 
    </bean>   
  
    <!-- 配置DAO -->
    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
    <bean id="userDao" parent="transactionBase" > 
        <property name="target" ref="userDaoTarget" />  
    </bean>
</beans>
第三种方式:使用拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory" 
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean> 

    <!-- 定义事务管理器(声明式的事务) --> 
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
  
    <bean id="transactionInterceptor" 
        class="org.springframework.transaction.interceptor.TransactionInterceptor"> 
        <property name="transactionManager" ref="transactionManager" /> 
        <!-- 配置事务属性 --> 
        <property name="transactionAttributes"> 
            <props> 
                <prop key="*">PROPAGATION_REQUIRED</prop> 
            </props> 
        </property> 
    </bean>
     
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
        <property name="beanNames"> 
            <list> 
                <value>*Dao</value>
            </list> 
        </property> 
        <property name="interceptorNames"> 
            <list> 
                <value>transactionInterceptor</value> 
            </list> 
        </property> 
    </bean> 
 
    <!-- 配置DAO -->
    <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>
第四种方式:使用tx标签配置的拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.bluesky" />

    <bean id="sessionFactory" 
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean> 

    <!-- 定义事务管理器(声明式的事务) --> 
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
   
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
            expression="execution(* com.bluesky.spring.dao.*.*(..))" />
        <aop:advisor advice-ref="txAdvice"
            pointcut-ref="interceptorPointCuts" />       
    </aop:config>     
</beans>
第五种方式:全注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.bluesky" />

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="sessionFactory" 
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean> 

    <!-- 定义事务管理器(声明式的事务) --> 
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
   
</beans>
此时在DAO上需加上@Transactional注解,如下:
package com.bluesky.spring.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;

import com.bluesky.spring.domain.User;

@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

    public List<User> listUsers() {
        return this.getSession().createQuery("from User").list();
    }
   
    
}


Spring配置总结
web.xml
载入Log4j配置
<context-param><!--Log4j配置 在同一容器中部署多个应用不能使用默认的webAppRootKey,必须指定唯一KEY,以免冲突-->
    <param-name>webAppRootKey</param-name>
    <param-value>itservice.root</param-value>
    <!--在log4j.properties中设置日志路径log4j.appender.file.File=${itservice.root}/WEB-INF/itservice.log-->
</context-param>
<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>



  载入Spring配置文件
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
    <!--可载入多个配置文件分隔符 , ;  \t \n -->
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>



  字符编码过滤器
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter-mapping>



配置延迟加载时使用OpenSessionInView
<filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>sessionFactoryBeanName</param-name>
       <!--指定对Spring配置中哪个sessionFactory使用OpenSessionInView-->
      <param-value>sessionFactory_itdb</param-value>
    </init-param>
  </filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
Struts-config.xml
<action input="/index.jsp" name="loginActionForm" parameter="method" path="/loginAction" scope="session" type="org.springframework.web.struts.DelegatingActionProxy" validate="true" />

<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property="contextConfigLocation" value="/WEB-INF/classes/action-servlet.xml" />
       <!--将spring配置中关于ACTION的配置独立到一个action-servlet.xml文件中-->
  </plug-in>
ApplicationContext.xml
<!--直接使用hibernate配置文件-->
<bean id="sessionFactory_itdb" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">
         <value>classpath:hibernate_itdb.cfg.xml</value>
    </property>
  </bean>



<!--使用JNDI DataSource-->
<bean id="it_dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
  <value>jdbc/itdb</value>
</property>
</bean>

<!-- Spring配置DataSource -->
  <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
       <value>classpath:init.properties</value>
    </property>
  </bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="${dataSource.driverClassName}"></property>
   <property name="url" value="${dataSource.url}"></property>
   <property name="username" value="${dataSource.username}"></property>
   <property name="password" value="${dataSource.password}"></property>
</bean>
<!-- *********************Hibernate*********************** -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
  <property name="mappingResources">
  <list>
    <value>com/usish/shweb/hbm/ShwebFile.hbm.xml</value>
    <value>com/usish/shweb/hbm/ShwebLog.hbm.xml</value>
  </list>
</property>
<property name="hibernateProperties">
  <props>
     <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
     <prop key="hibernate.show_sql">false</prop>
     <prop key="hibernate.jdbc.fetch_size">50</prop>
     <prop key="hibernate.jdbc.batch_size">30</prop>
     <prop key="hibernate.cache.use_second_level_cache">true</prop>
     <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
     <prop key="hibernate.cache.use_query_cache">true</prop>
  </props>
</property>
</bean>



<!--******************TransactionManager***********************-->
<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
   <property name="sessionFactory">
       <ref local="sessionFactory" />
   </property>
</bean>
<bean id="baseTxProxy"  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true">
  <property name="transactionManager">
    <ref bean="transactionManager" />
  </property>
  <property name="transactionAttributes">
    <props>
     <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
     <prop key="get*">PROPAGATION_REQUIRED</prop>
     <prop key="save*">PROPAGATION_REQUIRED</prop>
     <prop key="insert*">PROPAGATION_REQUIRED</prop>
     <prop key="update*">PROPAGATION_REQUIRED</prop>
     <prop key="delete*">PROPAGATION_REQUIRED</prop>
    </props>
  </property>
</bean>

<!--AOP TX-->
<tx:advice id="txAdvice" transaction-manager="txManager">
   <tx:attributes>
     <tx:method name="get*" propagation="NEVER"/>
     <tx:method name="find*" propagation="NEVER"/>
     <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="txBusinessMethods" expression="execution(* com.ztgame.blog.business.*BusinessImpl.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txBusinessMethods"/>
</aop:config>

<!--annotation TX-->
<tx:annotation-driven proxy-target-class="true" transaction-manager="txManager"/>



Spring编程式事物
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
      <property name="transactionManager">
        <ref bean="TransactionManager"/>
      </property>
    </bean>
    <bean id="courseService" class="com.test.CourseService">
      <property name="transactionTemplate">
        <ref bean="transactionTemplate"/>
      </property>
</bean>


private TransactionTemplate transactionTemplate;
    public void enrollStudent()...{
        transactionTemplate.execute(new TransactionCallback()...{
            public Object doInTransaction(TransactionStatus ts)...{
                try ...{
//                    需要事务控制的方法代码
                } catch (Exception e) ...{
                    ts.setRollbackOnly();  //回滚
                }
                return null;  //事务提交
            }   
        });
    }
}



7个事务策略:
1、  PROPAGATION_REQUIRED -- 支持当前的事务,如果不存在就创建一个新的。这是最常用的选择。
2 、 PROPAGATION_SUPPORTS -- 支持当前的事务,如果不存在就不使用事务。
3 、 PROPAGATION_MANDATORY -- 支持当前的事务,如果不存在就抛出异常。
4 、 PROPAGATION_REQUIRES_NEW -- 创建一个新的事务,并暂停当前的事务(如果存在)。
5 、 PROPAGATION_NOT_SUPPORTED -- 不使用事务,并暂停当前的事务(如果存在)。
6 、 PROPAGATION_NEVER -- 不使用事务,如果当前存在事务就抛出异常。
7 、 PROPAGATION_NESTED -- 如果当前存在事务就作为嵌入事务执行,否则与 PROPAGATION_REQUIRED 类似。

  
  5个隔离策略:  
  ISOLATION_DEFAULT  
  ISOLATION_READ_UNCOMMITED  
  ISOLATION_COMMITED  
  ISOLATION_REPEATABLE_READ  
  ISOLATION_SERIALIZABLE
●   未授权读取(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个数据则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
●   授权读取(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
●   可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
●   序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。


●   更新丢失(Lost update):两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。
●   脏读取(Dirty Reads):一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。
●   不可重复读取(Non-repeatable Reads):一个事务对同一行数据重复读取两次,但是却得到了不同的结果。例如,在两次读取的中途,有另外一个事务对该行数据进行了修改,并提交。
●   两次更新问题(Second lost updates problem):无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。
●   虚读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。

                                 Dirty reads          non-repeatable reads            phantom reads
SERIALIZABLE                   不会                   不会                               不会
REPEATABLE READ            不会                   不会                               会
READ COMMITTED             不会                   会                                  会
READ UNCOMMITTED         会                      会                                  会
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics