事務能夠用如下方式管理:mysql
EntityManagerFactory factory = Persistence.createEntityManagerFactory("PERSISTENCE_UNIT_NAME"); EntityManager entityManager = entityManagerFactory.createEntityManager(); Transaction transaction = entityManager.getTransaction() try { transaction.begin(); someBusinessCode(); transaction.commit(); } catch(Exception ex) { transaction.rollback(); throw ex; }
優勢:web
缺點:面試
Spring支持兩類事務管理spring
強烈建議使用聲明式事務。若是想知道其緣由,請閱讀下面的內容,不然,能夠直接跳轉到聲明式事務管理實現的部分。
如今,讓咱們細緻的分析每一種事務管理方法。sql
Spring Framework提供了兩種編程式事務管理方法。
a. 使用TransactionTemplate (Spring推薦這種實現):
Context Xml file:數據庫
<!-- Initialization for data source --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/TEST"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- Initialization for TransactionManager --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- Definition for ServiceImpl bean --> <bean id="serviceImpl" class="com.service.ServiceImpl"> <constructor-arg ref="transactionManager"/> </bean>
Service類:編程
public class ServiceImpl implements Service { private final TransactionTemplate transactionTemplate; // 使用構造器注入來使用PlatfromTransactionManager public ServiceImpl(PlatformTransactionManager transactionManager) { this.transactionTemplate = new TransactionTemplate(transactionManager); } public Object someServiceMethod() { return transactionTemplate.execute(new TransactionCallback() { //這段代碼在事務上下文中執行 public Object doInTransaction(TransactionStatus status) { updateOperation1(); return resultOfUpdateOperation2(); } }); }}
若是沒有返回值,就使用TransactionCallbackWithoutResult
匿名類。安全
transactionTemplate.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { updateOperation1(); updateOperation2(); } });
TransactionTemplate
類的實例是線程安全的,這些實例不包含任何會話狀態。TransactionTemplate
實例確實會維持配置信息狀態,因此即便多個類共享同一個TransactionTemplate
實例,若是一個類須要使用另外一種配置的TransactionTemplate
(好比不一樣的隔離級別),那麼就須要配置兩個不一樣的實例。b. 直接使用PlatformTransactionManager
實現微信
<!-- Initialization for data source --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/TEST"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- Initialization for TransactionManager --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
public class ServiceImpl implements Service { private PlatformTransactionManager transactionManager; public void setTransactionManager( PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // explicitly setting the transaction name is something that can only be done programmatically def.setName("SomeTxName"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = txManager.getTransaction(def); try { // execute your business logic here } catch (Exception ex) { txManager.rollback(status); throw ex; } txManager.commit(status); }
在進入聲明式事務管理以前,讓咱們看看如何選擇事務管理方式:ui
第一步:在spring應用程序上下文xml文件中定義事務管理器。
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/>
第二步:經過在spring應用程序上下文XML文件中添加如下條目,打開對事務註釋的支持。
<tx:annotation-driven transaction-manager="txManager"/>
或是在配置類中添加@EnableTransactionManagement
@Configuration @EnableTransactionManagement public class AppConfig { ... }
Spring建議只使用@Transactional來註解具體類(以及具體類的方法),而不是接口。
緣由是若是在接口上註解,而且使用基於類的代理(proxy-target-class="true")或是aop(mode="aspectj"),那麼事務註解將沒法被識別。
第三步:將註解添加在類(或是類的方法)或是接口(或是接口的方法上)
<tx:annotation-driven proxy-target-class="true">
默認配置爲proxy-target-class="false"
@Transactional
註解能夠放在接口,接口方法,類或是類方法上如今讓咱們瞭解一下@Transactional
的屬性:@Transactional (isolation=Isolation.READ_COMMITTED)
Isolation.DEFAULT
READ_COMMITTED
防止髒讀;會發生不可重複的讀取和幻讀。
READ_UNCOMMITTED
會出現髒讀,不可重複讀和幻讀。便可以看到事務還沒有提交的數據
REPEATABLE_READ
可重複讀。會出現幻讀
序列化
防止髒讀,幻讀和不可重複讀
@Transactional(timeout=60)
默認爲底層事務系統的默認超時。
當事務超過該時間沒有響應時,則會對底層系統發出回滾請求
@Transactional(propagation=Propagation.REQUIRED)
默認的傳播級別爲Required
。其它的選項如REQUIRES_NEW, MANDATORY, SUPPORTS, NOT_SUPPORTED, NEVER, 和NESTED
REQUIRED
表示若是當前沒有活躍的事務上下文,目標方法將沒法運行。若是在調用此方法以前已經啓動了事務管理,那麼它將在相同的事務中繼續,或者在調用此方法時將當即開始新的事務。
REQUIRES_NEW
表示每次調用目標方法時都必須啓動新的事務。若是已有事務,它將暫停。
MANDATORY
表示目標方法須要運行中的事務。若是沒有事務,它將拋出異常。
SUPPORTS
不管是否有事務上下文,目標方法能夠執行。若是當前有事務上下文,它將在同一個上下文中運行。若是沒有,它仍將執行。這個選項適合獲取數據的方法。
NOT_SUPPORTED
目標方法無需傳播事務上下文。
NEVER
若是在事務上下文中執行目標方法,則拋出異常
@Transactional (rollbackFor=Exception.class)
rollbackFor=RunTimeException.class
RuntimeException
,事務就會回滾。@Transactional (noRollbackFor=IllegalStateException.class)
若是該異常出現時,則不進行回滾
最後,也是最重要的一個問題,@Transactional
註解究竟應該放在哪一層?Service層仍是Dao層?
LazyInitializationException
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~