在前面我寫過一篇關於事務的文章,你們能夠先去看看那一篇再看這一篇,學習起來會更加駕輕就熟
連接:https://blog.csdn.net/pjh88/article/details/107574137java
事務管理器:PlatformTransactionManager
PlatformTransactionManager是事務的管理器,他提供了咱們經常使用的事務操做方法mysql
爲何PlatformTransactionManager是接口類型?
由於不一樣的dao層技術有不一樣的實現類
Dao層是jdbc時:org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao層是mybatis時:org.springframework.orm.hibernate5.HibernateTransactionManager程序員
事務的定義信息對象:TransactionDefinition
TransactionDefinition
裏面的方法spring
**sql
**數據庫
ISOLATION_READ_UNCOMMITTED(讀未提交)express
實質:一個事務讀取另外一個事務未提交的數據apache
例子:老闆要給程序員發工資,程序員的工資是3.6萬/月。可是發工資時老闆不當心按錯了數字,按成3.9萬/月,該錢已經打到程序員的戶口,可是事務尚未提交,就在這時,程序員去查看本身這個月的工資,發現比往常多了3千元,覺得漲工資了很是高興。可是老闆及時發現了不對,立刻回滾差點就提交了的事務,將數字改爲3.6萬再提交。編程
分析:實際程序員這個月的工資仍是3.6萬,可是程序員看到的是3.9萬。他看到的是老闆還沒提交事務時的數據。這就是髒讀。數據結構
ISOLATION_READ_COMMITTED(讀已提交)
實質:一個用戶讀取另外一個用戶已提交的數據
事例:程序員拿着信用卡去享受生活(卡里固然是隻有3.6萬),當他埋單時(程序員事務開啓),收費系統事先檢測到他的卡里有3.6萬,就在這個時候!!程序員的妻子要把錢所有轉出充當家用,並提交。當收費系統準備扣款時,再檢測卡里的金額,發現已經沒錢了(第二次檢測金額固然要等待妻子轉出金額事務提交完)。程序員就會很鬱悶,明明卡里是有錢的…
分析:這就是讀提交,如有事務對數據進行更新(UPDATE)操做時,讀操做事務要等待這個更新操做事務提交後才能讀取數據,能夠解決髒讀問題。但在這個事例中,出現了一個事務範圍內兩個相同的查詢卻返回了不一樣數據,這就是不可重複讀。
ISOLATION_REPEATABLE_READ(重複讀)
實質:一個事務在讀取數據時,其餘事務不容許進行修改操做
事例:程序員拿着信用卡去享受生活(卡里固然是隻有3.6萬),當他埋單時(事務開啓,不容許其餘事務的UPDATE修改操做),收費系統事先檢測到他的卡里有3.6萬。這個時候他的妻子不能轉出金額了。接下來收費系統就能夠扣款了。
分析:重複讀能夠解決不可重複讀問題。寫到這裏,應該明白的一點就是,不可重複讀對應的是修改,即UPDATE操做。可是可能還會有幻讀問題。由於幻讀問題對應的是插入INSERT操做,而不是UPDATE操做。
ISOLATION_SERIALIZABLE(幻讀)
事例:程序員某一天去消費,花了2千元,而後他的妻子去查看他今天的消費記錄(全表掃描FTS,妻子事務開啓),看到確實是花了2千元,就在這個時候,程序員花了1萬買了一部電腦,即新增INSERT了一條消費記錄,並提交。當妻子打印程序員的消費記錄清單時(妻子事務提交),發現花了1.2萬元,彷佛出現了幻覺,這就是幻讀。
**
**
REQUIRED:若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。通常的選擇(默認值)
SUPPORTS:支持當前事務,若是當前沒有事務,就以非事務方式執行(沒有事務)
MANDATORY:使用當前的事務,若是當前沒有事務,就拋出異常
REQUERS_NEW:新建事務,若是當前在事務中,把當前事務掛起。
NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起
NEVER:以非事務方式運行,若是當前存在事務,拋出異常
NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行 REQUIRED 相似的操做
超時時間:默認值是-1,沒有超時限制。若是有,以秒爲單位進行設置
是否只讀:建議查詢時設置爲只讀
TransactionStatus接口提供的是事務具體的運行狀態,方法以下
編程式事務控制的三大對象
PlatformTransactionManager
TransactionDefinition
TransactionStatus
Spring的聲明式事務控制顧名思義就是使用聲明的方式來處理事務,這裏的聲明指的是在配置文件中聲明,Spring配置文件中的聲明式處理來代替代碼式的事務處理
聲明式事務處理的做用
事務處理是不侵入開發的組件,具體來講,業務邏輯對象不會意識帶正在處於事務處理之中,事實上也應該如此,由於事務管理是出於系統層面的職務,而不是業務邏輯處理的一部分,若是要改變事務管理策劃的話,也只須要在定義文件中從新配置便可
在不須要事務管理的時候,只要在設定的文件上修改一下,便可移除事務管理服務,不須要改變代碼從新編譯,這樣維護起來更加方便
Spring事務控制的底層就是AOP
切點:須要被事務管理的方法,即業務方法
通知/加強:事務加強
切面:兩者結合
1.建立數據庫和實體
表名:account
字段名:moey--錢,Name--客戶名
CREATE TABLE account( NAME VARCHAR(10), money DOUBLE );
插入三個字段值
INSERT INTO account VALUE('tom',1),('bob',2),('jack',3);
2.須要導入的座標
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>spring-mysql</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> </dependencies> </project>
3.建立實體類
package com.pjh.account; public class account { private double money; private String name; @Override public String toString() { return "account{" + "money=" + money + ", name='" + name + '\'' + '}'; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
4.dao層(執行語句,與數據庫交互)
接口
package com.pjh.dao; public interface ServiceDao { public void inman(String inName,double money); public void outman(String outName,double money); }
實現類
package com.pjh.dao.imp; import com.pjh.dao.ServiceDao; import org.springframework.jdbc.core.JdbcTemplate; public class ServiceDaoImp implements ServiceDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void inman(String inName, double money) { jdbcTemplate.update("update account set money=money-? where name =?",money,inName); } public void outman(String outName, double money) { jdbcTemplate.update("update account set money=money+? where name =?",money,outName); } }
5.service層
接口
package com.pjh.service; public interface service { public void trasfer(String inName,String outName,double money); }
實現類
package com.pjh.service.Imp; import com.pjh.dao.imp.ServiceDaoImp; import com.pjh.service.service; import org.springframework.beans.factory.annotation.Autowired; public class serviceImp implements service { private ServiceDaoImp serviceDaoImp; public void setServiceDaoImp(ServiceDaoImp serviceDaoImp) { this.serviceDaoImp = serviceDaoImp; } public void trasfer(String inName, String outName, double money) { serviceDaoImp.inman(inName,money); serviceDaoImp.outman(outName,money); } }
6.applicationContext配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="password" value="${jdbc.password}"/> <property name="user" value="${jdbc.name}"/> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="serviceDaoImp" class="com.pjh.dao.imp.ServiceDaoImp"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <!--目標對象 內部方法就是切點--> <bean id="serviceImp" class="com.pjh.service.Imp.serviceImp"> <property name="serviceDaoImp" ref="serviceDaoImp"></property> </bean> <!--配置平臺事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--通知 事務的加強--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice> <!--配置事務的織入--> <aop:config proxy-target-class="true"> <aop:pointcut id="txPointcut" expression="execution(* com.pjh.service.Imp.serviceImp.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> <context:property-placeholder location="classpath:jdbc.properties"/> <context:component-scan base-package="com.pjh"/> </beans>
7.主函數
package com.pjh.control; import com.pjh.service.Imp.serviceImp; import com.pjh.service.service; import org.springframework.context.support.ClassPathXmlApplicationContext; public class control2 { public static void main(String[] args) { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); service bean1 =(service) classPathXmlApplicationContext.getBean(service.class); bean1.trasfer("tom","jack",100); } }
結果
成功轉帳
**
**
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*"/> </tx:attributes> </tx:advice>
<tx:method >:表明事務參數方法的配置
這個部分必定要重點掌握這是核心
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/> name:切點方法名稱 isolation:事務的隔離級別 propogation:事務的傳播行爲 timeout:超時時間 read-only:是否只讀
1.dao層
package com.pjh.dao.imp; import com.pjh.dao.ServiceDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository("ServiceDaoImp") public class ServiceDaoImp implements ServiceDao { @Autowired private JdbcTemplate jdbcTemplate; public void inman(String inName, double money) { jdbcTemplate.update("update account set money=money-? where name =?",money,inName); } public void outman(String outName, double money) { jdbcTemplate.update("update account set money=money+? where name =?",money,outName); } }
2.service層
package com.pjh.service.Imp; import com.pjh.dao.imp.ServiceDaoImp; import com.pjh.service.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service("serviceImp") @Transactional public class serviceImp implements service { @Autowired private ServiceDaoImp serviceDaoImp; public void trasfer(String inName, String outName, double money) { serviceDaoImp.inman(inName,money); //int a=1/0; serviceDaoImp.outman(outName,money); } }
3.編寫applicationContext的內容
<!--組件掃描--> <context:component-scan base-package="com.pjh"/> <!--事務的註解驅動--> <tx:annotation-driven/>
小總結
1.使用 @Transactional 在須要進行事務控制的類或是方法上修飾,註解可用的屬性同 xml 配置方式,例如隔離級別、傳播行爲等。
註解使用在類上,那麼該類下的全部方法都使用同一套註解參數配置。
使用在方法上,不一樣的方法能夠採用不一樣的事務參數配置。
2.Xml配置文件中要開啓事務的註解驅動<tx:annotation-driven />