您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Spring事務是怎么實現的”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Spring事務是怎么實現的”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
1.Spring事務底層是基于數據庫事務和AOP機制的
2.首先對于使用了@Transactional注解的Bean,Spring會創建一個代理對象作為Bean
3.當調用代理對象的方法時,會先判斷該方法上是否加了@Transactional注解
4.如果加了,那么則利用事務管理器創建一個數據庫連接
5.并且修改數據庫連接的autocommit屬性為false,禁止此連接的自動提交,這是實現Spring事務非常重要的一步
6.然后執行當前方法,方法中會執行sql
7.執行完當前方法后,如果沒有出現異常就直接提交事務
8.如果出現了異常,并且這個異常是需要回滾的就會回滾事務,否則仍然提交事務
注:
1.Spring事務的隔離級別對應的就是數據庫的隔離級別
2.Spring事務的傳播機制是Spring事務自己實現的,也是Spring事務中最復雜的
3.Spring事務的傳播機制是基于數據庫連接來做的,一個數據庫連接就是一個事務,如果傳播機制配置為需要新開一個事務,那么實際上就是先新建一個數據庫連接,在此新數據庫連接上執行sql
事務幾種實現方式
(1)編程式事務管理對基于 POJO 的應用來說是唯一選擇。我們需要在代碼中調用beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。
(2)基于 TransactionProxyFactoryBean的聲明式事務管理
(3)基于 @Transactional 的聲明式事務管理
(4)基于Aspectj AOP配置事務
1、transactionTemplate
此種方式是自動的事務管理,無需手動開啟、提交、回滾。
配置事務管理器
<!-- 配置事務管理器 ,封裝了所有的事務操作,依賴于連接池 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
配置事務模板對象
<!-- 配置事務模板對象 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean>
測試
@Controller @RequestMapping("/tx") @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class TransactionController { @Resource public TransactionTemplate transactionTemplate; @Resource public DataSource dataSource; private static JdbcTemplate jdbcTemplate; private static final String INSERT_SQL = "insert into cc(id) values(?)"; private static final String COUNT_SQL = "select count(*) from cc"; @Test public void TransactionTemplateTest(){ //獲取jdbc核心類對象,進而操作數據庫 jdbcTemplate = new JdbcTemplate(dataSource); //通過注解 獲取xml中配置的 事務模板對象 transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); //重寫execute方法實現事務管理 transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { jdbcTemplate.update(INSERT_SQL, "33"); //字段sd為int型,所以插入肯定失敗報異常,自動回滾,代表TransactionTemplate自動管理事務 } }); int i = jdbcTemplate.queryForInt(COUNT_SQL); System.out.println("表中記錄總數:"+i); } }
2、PlatformTransactionManager
使用 事務管理器 PlatformTransactionManager 對象,PlatformTransactionManager是DataSourceTransactionManager實現的接口類
此方式,可手動開啟、提交、回滾事務。
只需要:配置事務管理
<!-- 配置事務管理 ,封裝了所有的事務操作,依賴于連接池 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
測試
@Controller @RequestMapping("/tx") @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class TransactionController { @Resource public PlatformTransactionManager transactionManager;//這里就是將配置數據管理對象注入進來, @Resource public DataSource dataSource; private static JdbcTemplate jdbcTemplate; private static final String INSERT_SQL = "insert into cc(id) values(?)"; private static final String COUNT_SQL = "select count(*) from cc"; @Test public void showTransaction(){ //定義使用隔離級別,傳播行為 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //事務狀態類,通過PlatformTransactionManager的getTransaction方法根據事務定義獲取;獲取事務狀態后,Spring根據傳播行為來決定如何開啟事務 TransactionStatus transaction = transactionManager.getTransaction(def); jdbcTemplate = new JdbcTemplate(dataSource); int i = jdbcTemplate.queryForInt(COUNT_SQL); System.out.println("表中記錄總數:"+i); try { jdbcTemplate.update(INSERT_SQL,"2"); jdbcTemplate.update(INSERT_SQL,"是否");//出現異常,因為字段為int類型,會報異常,自動回滾 transactionManager.commit(transaction); }catch (Exception e){ e.printStackTrace(); transactionManager.rollback(transaction); } int i1 = jdbcTemplate.queryForInt(COUNT_SQL); System.out.println("表中記錄總數:"+i1); } }
1、基于Aspectj AOP開啟事務
配置事務通知
<!-- 配置事務增強 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" /> </tx:attributes> </tx:advice>
配置織入
<!-- aop代理事務。掃描 cn.sys.service 路徑下所有的方法 --> <aop:config> <!-- 掃描 cn.sys.service 路徑下所有的方法,并加入事務處理 --> <aop:pointcut id="tx" expression="execution(* cn.sys.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="tx" /> </aop:config>
一個完整的例子
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- 創建加載外部Properties文件對象 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:dataBase.properties"></property> </bean> <!-- 引入redis屬性配置文件 --> <import resource="classpath:redis-context.xml"/> <!-- 配置數據庫連接資源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" scope="singleton"> <property name="driverClassName" value="${driver}"></property> <property name="url" value="${url}"></property> <property name="username" value="${username}"></property> <property name="password" value="${password}"></property> <property name="maxActive" value="${maxActive}"></property> <property name="maxIdle" value="${maxIdle}"></property> <property name="minIdle" value="${minIdle}"></property> <property name="initialSize" value="${initialSize}"></property> <property name="maxWait" value="${maxWait}"></property> <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}"></property> <property name="removeAbandoned" value="${removeAbandoned}"></property> <!-- 配置sql心跳包 --> <property name= "testWhileIdle" value="true"/> <property name= "testOnBorrow" value="false"/> <property name= "testOnReturn" value="false"/> <property name= "validationQuery" value="select 1"/> <property name= "timeBetweenEvictionRunsMillis" value="60000"/> <property name= "numTestsPerEvictionRun" value="${maxActive}"/> </bean> <!--創建SQLSessionFactory對象 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:MyBatis_config.xml"></property> </bean> <!-- 創建MapperScannerConfigurer對象 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.sys.dao"></property> </bean> <!-- 配置掃描器 IOC 注解 --> <context:component-scan base-package="cn.sys" /> <!-- 配置事務管理 ,封裝了所有的事務操作,依賴于連接池 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事務模板對象 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> <!-- 配置事務增強 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" /> </tx:attributes> </tx:advice> <!-- aop代理事務 --> <aop:config> <aop:pointcut id="tx" expression="execution(* cn.sys.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="tx" /> </aop:config> </beans>
這樣就算是給 cn.sys.service下所有的方法加入了事務
也可以用springboot的配置類方式:
package com.junjie.test; @Configurationpublic class TxAnoConfig { /*事務攔截類型*/ @Bean("txSource") public TransactionAttributeSource transactionAttributeSource() { NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); /*只讀事務,不做更新操作*/ RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, Collections.singletonList(new RollbackRuleAttribute(Exception.class))); requiredTx.setTimeout(60); Map<String, TransactionAttribute> txMap = new HashMap<>(); txMap.put("*", requiredTx); source.setNameMap(txMap); return source; } /** * 切面攔截規則 參數會自動從容器中注入 */ @Bean public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) { AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor(); pointcutAdvisor.setAdvice(txInterceptor); pointcutAdvisor.setExpression("execution (* com.cmb..*Controller.*(..))"); return pointcutAdvisor; } /*事務攔截器*/ @Bean("txInterceptor") TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx) { return new TransactionInterceptor(tx, transactionAttributeSource()); } }
2、基于注解的 @Transactional 的聲明式事務管理
@Transactional public int saveRwHist(List list) { return rwDao.saveRwHist(list); }
這個注解的開啟需要在spring.xml里加上一個開啟注解事務的配置
讀到這里,這篇“Spring事務是怎么實現的”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。