??xml version="1.0" encoding="utf-8" standalone="yes"?> Spring对声明式事务理的支持是通过它的AOP框架实现的。这样做是非常自然的Q因Z务是pȝU的Q凌驾于应用的主要功能之上的?/p>
在Spring里,事务属性是对事务策略如何应用到Ҏ(gu)的描q。这个描q包括:(x)传播行ؓ(f)、隔ȝ别、只LC、事务超旉?br />
传播行ؓ(f)Q?br />
PROPAGATION_MANDATORY:表示该方法必运行在一个事务中。如果当前事务不存在Q将抛出一个异常?br />
PROPAGATION_NESTED:表示如果当前已经存在一个事务,则该Ҏ(gu)应当q行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交或回滚。如果当前事务不存在Q那么它看v来和PROPAGATION_REQUIRED没有两样?br />
PROPAGATION_NEVER:表示当前的方法不应该q行在一个事务上下文中。如果当前存在一个事务,则会(x)抛出一个异常?br />
PROPAGATION_NOT_SUPPORTED:表示该方法不应在事务中运行。如果一个现有的事务正在q行中,它将在该Ҏ(gu)的运行期间被挂v?br />
PROPAGATION_REQUIRED:表示当前Ҏ(gu)必须q行在一个事务中。如果一个现有的事务正在q行中,该方法将q行在这个事务中。否则的话,要开始一个新的事务?br />
PROPAGATION_REQUIRES_NEW:表示当前Ҏ(gu)必须q行在它自己的事务里。它?yu)启动一个新的事务。如果有事务q行的话Q将在这个方法运行期间被挂v?br />
PROPAGATION_SUPPORTS:表示当前Ҏ(gu)不需要事务处理环境,但如果有一个事务已l在q行的话Q这个方法也可以在这个事务里q行?/p>
传播规则回答了一个问题:(x)是新的事务是否要被启动或是被挂P或者方法是否要在事务环境中q行?/p>
隔离U别Q在一个典型的应用中,多个事务q发q行Q经怼(x)操作同一个数据来完成它们的Q务。ƈ发,虽然是必ȝQ但?x)导致下面问题?x) 只读Q如果一个事务只对后端是据库执行L作,数据库就可能利用事务只读的特性,使用某些优化措施。通过声明一个事务ؓ(f)只读Q你q了后端数据库一个机?x),来应用那些它认?f)合适的优化措施。因为只ȝ优化措施是在事务启动时由后端数据库实施的Q所以,只有那些具有可能启动新事务的传播行为的Ҏ(gu)的事务标记成只读才有意义(PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED) TransactionProxyFactoryBean参照一个方法的事务属性,军_如何在那个方法上执行事务{略?br />
除了transactionAttributeSource对象l入到TransactionProxyFactoryBean的transactionAttributeSource属性中外,q有一U简单的Ҏ(gu)。发展到现在QTransactionProxyFactoryBean也有一个transactionAttributes属性ؓ(f)transactionProperties.
Spring对程序控制事务管理的支持和EJB的有很大不同。EJB的事务管理和JTA密不可分Q和EJB不同的是QSpring使用了一U回调机Ӟ把真实的事务实现从事务代码中抽象出来。选择E序控制事务理q是声明式事务管理,很大E度上是在细_度控制与简便操作之间做出决定。当你在代码中编写事务时Q你能精控制事务的边界Q在你希望的地方_的开始和l束。典型的情况下,你不需要程序控制事务所提供的细_度控制Q你?x)选择在上下文定义文g中声明你的事务?/p>
1、脏读:(x)脏读发生在一个事务读取了被另一个事务改写但q未提交的数据时。如果这些改变在E后被回滚,那么W一个事务读取的数据是无效的?br />
2、不可重复读Q不可重复读发生在一个事务执行相同的查询2ơ或2ơ以上,但每一ơ查询结果都不同时。这通常是由于另一个ƈ发事务在2ơ查询之间更C数据?br />
3、读:(x)q读和不可重复读怼。当一个事务读取几行纪录后Q另一个ƈ发事务插入一些记录,q读发生了。隔ȝ别有如下几个Q?br />
ISOLATION_DEFAULT:使用后端数据库默认的隔离U别
ISOLATION_READ_UNCOMMITTED:允许你读取还未提交的改变了的数据Q可能导致脏诅R诅R不可重复读
ISOLATION_READ_COMMITTED:允许在ƈ发事务已l提交后d。可防止脏读Q但q读和不可重复读仍可能发生?br />
ISOLATION_REPEATABLE_READ:对相同字D늚多次d的结果是一致的Q除非数据被事务本n改变。可防止脏读和不可重复读Q但q读仍可能发生?br />
ISOLATION_SERIALIZABLE:完全服从ACID的隔ȝ别,保不发生脏诅R不可重复读和诅R这在所有隔ȝ别中也是最慢的?/p>
<?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-2.0.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDatasource</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- q个对象有一个gؓ(f)courseService的id.当应用从应用上下文里h一个courseServiceӞ它将得到一个被
TransactionProxyFactoryBean包裹的实例?nbsp;-->
<bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 代理所实现的接?nbsp;-->
<property name="proxyInterfaces">
<list>
<value>
com.springinaction.training.service.CourseService
</value>
</list>
</property>
<!-- 被代理的对象 -->
<property name="target">
<ref bean="courseServiceTarget"/>
</property>
<!-- 事务理?nbsp;-->
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<!-- 事务的属性源 -->
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
<!-- 要知道尽可以改变MatchAlwaysTransactionAttributeSource的事务属性参敎ͼ但它Lq回相同的事务属性,?br />
不关心参与交易的哪一个方法。当你有一个相对简单的应用Q把同样的事务策略应用到所有方法都没问题时Q用MatchAlwaysT
ransactionAttributeSourceq当好。但是,在那些更为复杂的应用中,你很可能需要对不同的方法应用不同的事务{略。在那样
情况下,你需要在应用何种{略的问题上做更多精的控制?nbsp;-->
<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute">
<ref bean="myTransactionAttribute"/>
</property>
</bean>
<!-- 定义事务{略 -->
<bean id="myTransactionAttribute" class="org.springframework.transaction.interceptor.DefaultTransactionAttribute">
<!-- 传播行ؓ(f) -->
<property name="propagationBehaviorName">
<value>PROPAGATION_REQUIRES_NEW</value>
</property>
<!-- 隔离U别 -->
<property name="isolationLevelName">
<value>ISOLATION_REPEATABLE_READ</value>
</property>
</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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDatasource</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- q个对象有一个gؓ(f)courseService的id.当应用从应用上下文里h一个courseServiceӞ它将得到一个被
TransactionProxyFactoryBean包裹的实例?nbsp;-->
<bean id="courseService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 代理所实现的接?nbsp;-->
<property name="proxyInterfaces">
<list>
<value>
com.springinaction.training.service.CourseService
</value>
</list>
</property>
<!-- 被代理的对象 -->
<property name="target">
<ref bean="courseServiceTarget"/>
</property>
<!-- 事务理?nbsp;-->
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<!-- 事务的属性源 -->
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
<!-- NameMatchTransactionAttributeSource的properties属性把Ҏ(gu)名映到事务属性描q器上。注意CourseException
用一个负h记。异常可以用负号或正h讎ͼ当负号异常抛出时Q将触发回滚;相反的,正号异常表示事务仍可提交Q即使这个异常抛?nbsp;-->
<bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ,readOnly,
-CourseException
</prop>
<!-- q可以用通配W?nbsp;-->
<prop key="get*">
PROPAGATION_SUPPORTS
</prop>
</props>
</property>
</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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/trainingDatasource</value>
</property>
</bean>
<!-- 理Hibernate资源Q在应用的整个生命周期里Q你只要保存一个SessionFactory实例可以了?/span>-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 先要知道q接哪个数据?nbsp;-->
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<!-- Hibernate本n有数十个属性,通过q些属性你可以控制它的行为。当在Spring之外使用Hibernage的时候,
Hibernate在应用的class path下的某个地方L一个名叫hibernate.properties的文Ӟq用它来q行配置?br />
然而,用Spring׃需要在一个独立的属性文仉理q些配置?nbsp;-->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<!-- 同样Q你也要告诉Spring从哪里读取Hibernate.hbm.xml映射文g -->
<property name="mappingResources">
<list>
<value>Student.hbm.xml</value>
</list>
</property>
<!-- q有一U简单的Ҏ(gu)讄映射文g资源,你可以用你应用的class path下的一个子路径来配|?br />
mappingDirectoryLocation属性,spring找到这个\径下的每?.hbm.xml文gQ来配置SessionFactory -->
<property name="mappingDirectoryLocations">
<list>
<value>classpath:/com/springinaction/training/model</value>
</list>
</property>
</bean>
<!-- 如果把这个模版对象织入到一个个DAOBean中显得很ȝ的时候,可以使用Spring自动q接功能来将模版对象隐士的织入到
DAObean. -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
</beans>
]]>
把操作创建成对象Q?br />
插入Q?br />
查询Q?br />