最近有個朋友去面試JAVA,問了我spring事務(wù)的事情萤彩,雖然之前有學(xué)過猎荠,但是沒有融會貫通坚弱,回答得很淺蜀备。這幾天重新學(xué)習(xí)研究了下,結(jié)合《Spring實戰(zhàn)》和網(wǎng)上關(guān)于spring事務(wù)的博客文章荒叶,總結(jié)一下碾阁。
參考文章:
1、事務(wù)初識
事務(wù)是邏輯上的一組操作些楣,要么全部成功脂凶,要么全部失敗。
事務(wù)具有ACID特性愁茁,參考百度百科蚕钦,具體如下:
原子性(Atomicity):整個事務(wù)中的所有操作,要么全部完成鹅很,要么全部不完成嘶居,不可能停滯在中間某個環(huán)節(jié)。
一致性(Consistency):事務(wù)必須始終保持系統(tǒng)處于一致的狀態(tài)促煮,不管在任何給定的時間并發(fā)事務(wù)有多少邮屁。
隔離性(Isolation):隔離狀態(tài)執(zhí)行事務(wù),使它們好像是系統(tǒng)在給定時間內(nèi)執(zhí)行的唯一操作菠齿。
持久性(Durability):在事務(wù)完成以后樱报,該事務(wù)對數(shù)據(jù)庫所作的更改便持久的保存在數(shù)據(jù)庫之中,并不會被回滾泞当。
2迹蛤、核心接口API
如上圖,Spring事務(wù)管理高層抽象主要有3個:
PlatformTransactionManager :事務(wù)管理器(用來管理事務(wù)襟士,包含事務(wù)的提交盗飒,回滾)
TransactionDefinition :事務(wù)定義信息(隔離,傳播陋桂,超時逆趣,只讀)
TransactionStatus :事務(wù)具體運行狀態(tài)
2.1 PlatformTransactionManager核心事務(wù)管理器
是Spring的事務(wù)管理器核心接口。
Spring本身并不支持事務(wù)實現(xiàn)嗜历,只是負責包裝底層事務(wù)宣渗,應(yīng)用底層支持什么樣的事務(wù)策略,Spring就支持什么樣的事務(wù)策略梨州。
里面提供了常用的操作事務(wù)的方法:
TransactionStatus getTransaction(TransactionDefinition definition):獲取事務(wù)狀態(tài)信息
void commit(TransactionStatus status):提交事務(wù)
void rollback(TransactionStatus status):回滾事務(wù)
Public interface PlatformTransactionManager()...{
// 由TransactionDefinition得到TransactionStatus對象
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
Void commit(TransactionStatus status) throws TransactionException;
// 回滾
Void rollback(TransactionStatus status) throws TransactionException;
}
2.1.1 JDBC事務(wù)
<bean id="transactionManager" class="org.springframework.jdbc.datasourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
DataSource TransactionManager:使用JDBC和iBatis進行持久化數(shù)據(jù)時使用
2.1.2 Hibernate事務(wù)
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Hibernate TransactionManager:使用Hibernate 3.0進行持久化數(shù)據(jù)時使用
2.1.3 Java持久化API事務(wù)(JPA)
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
JpaTransactionManager:使用JPA進行持久化時使用
2.1.4 Java原生API事務(wù)
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager" />
</bean>
JtaTransactionManager :如果沒有使用上述的事務(wù)管理痕囱,或者在一個事務(wù)跨越多個事務(wù)管理源時使用
2.2 TransactionDefinition信息對象
該接口定義了一些基本事務(wù)屬性
public interface TransactionDefinition {
int getPropagationBehavior(); // 返回事務(wù)的傳播行為
int getIsolationLevel(); // 返回事務(wù)的隔離級別,事務(wù)管理器根據(jù)它來控制另外一個事務(wù)可以看到本事務(wù)內(nèi)的哪些數(shù)據(jù)
int getTimeout(); // 返回事務(wù)必須在多少秒內(nèi)完成
boolean isReadOnly(); // 事務(wù)是否只讀暴匠,事務(wù)管理器能夠根據(jù)這個返回值進行優(yōu)化鞍恢,確保事務(wù)是只讀的
}
2.3 TransactionStatus運行狀態(tài)
該接口定義了事務(wù)具體的運行狀態(tài)
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢復(fù)點
void setRollbackOnly(); // 設(shè)置為只回滾
boolean isRollbackOnly(); // 是否為只回滾
boolean isCompleted; // 是否已完成
}
3、編程式事務(wù)
3.1 編程式和聲明式事務(wù)的區(qū)別
Spring提供了對編程式事務(wù)和聲明式事務(wù)的支持,編程式事務(wù)允許用戶在代碼中精確定義事務(wù)的邊界帮掉,而聲明式事務(wù)(基于AOP)有助于用戶將操作與事務(wù)規(guī)則進行解耦弦悉。
簡單地說,編程式事務(wù)侵入到了業(yè)務(wù)代碼里面蟆炊,但是提供了更加詳細的事務(wù)管理稽莉;而聲明式事務(wù)由于基于AOP,所以既能起到事務(wù)管理的作用涩搓,又可以不影響業(yè)務(wù)代碼的具體實現(xiàn)污秆。
3.2 如何實現(xiàn)編程式事務(wù)?
spring提供了兩種編程式事務(wù)管理缩膝,分別是使用TransactionTemplate和使用PlatformTransactionManager混狠。
3.2.1 使用TransactionTemplate
采用TransactionTemplate和采用其他Spring模板一樣,使用回調(diào)方法疾层,把應(yīng)用程序從處理取得和釋放資源中解放出來将饺。TransactionTemplate是線程安全的。代碼示例如下:
TransactionTemplate tt = new TransactionTemplate(); // 新建一個TransactionTemplate
Object result = tt.execute(
new TransactionCallback(){
public Object doTransaction(TransactionStatus status){
updateOperation();
return resultOfUpdateOperation();
}
}); // 執(zhí)行execute方法進行事務(wù)管理
使用TransactionCallback()可以返回一個值痛黎。如果使用TransactionCallbackWithoutResult則沒有返回值予弧。
3.2.2 使用PlatformTransactionManager
示例代碼如下:
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); //定義一個某個框架平臺的TransactionManager,如JDBC湖饱、Hibernate
dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 設(shè)置數(shù)據(jù)源
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定義事務(wù)屬性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 設(shè)置傳播行為屬性
TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 獲得事務(wù)狀態(tài)
try {
// 數(shù)據(jù)庫操作
dataSourceTransactionManager.commit(status);// 提交
} catch (Exception e) {
dataSourceTransactionManager.rollback(status);// 回滾
}
4掖蛤、聲明式事務(wù)
4.1 配置方式
根據(jù)代理機制的不同,總結(jié)了五種Spring事務(wù)的配置方式井厌,配置文件如下:
第一種方式:每個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>
<!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
<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">
<!-- 配置事務(wù)管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userDaoTarget" />
<property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
<!-- 配置事務(wù)屬性 -->
<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>
<!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
<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">
<!-- 配置事務(wù)管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事務(wù)屬性 -->
<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>
<!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
<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" />
<!-- 配置事務(wù)屬性 -->
<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>
<!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
<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>
<!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
<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();
}
....
}