激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring中事務管理的四種方法(銀行轉賬為例)

Spring中事務管理的四種方法(銀行轉賬為例)

2021-04-29 11:02皮卡丘啾啾 Java教程

這篇文章主要給大家介紹了關于Spring中事務管理的四種方法,文中是以銀行轉賬為例,通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

本文配套示例代碼下載地址(完整可運行,含sql文件,下載后請修改數據庫配置):點擊這里下載

一、事務的作用

 

  將若干的數據庫操作作為一個整體控制,一起成功或一起失敗。

  原子性:指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。

  一致性:指事務前后數據的完整性必須保持一致。

  隔離性:指多個用戶并發訪問數據庫時,一個用戶的事務不能被其他用戶的事務所干擾,多個并發事務之間數據要相互隔離。

  持久性:指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,即時數據庫發生故障也不應該對其有任何影響。

二、spring事務管理高層抽象主要包括3個接口

 

  --platform transactionmanager 事務管理器(提交、回滾事務)

     spring為不同的持久化框架提供了不同的platform transactionmanager接口實現。如:

        使用spring jdbc或ibatis進行持久化數據時使用datasourcetransactionmanager

        使用hibernate3.0版本進行持久化數據時使用hibernatetransactionmanager

  --transactiondefinition 事務定義信息(隔離、傳播、超時、只讀)

        臟讀:一個事務讀取了另一個事務改寫但還未提交的數據,如果這些數據被回滾,則讀到的數據是無效的。

        不可重復讀:在同一事務中,多次讀取同一數據返回的結果有所不同。

        幻讀:一個事務讀取了幾行記錄后,另一個事務插入一些記錄,幻讀就發生了。再后來的查詢中,第一個事務就會發現有些原來沒有的記錄。

        事務隔離級別:(五種)

  •     default--使用后端數據庫默認的隔離級別(spring中的選擇項)
  •     read_uncommited--允許你讀取還未提交的改變了的數據??赡軐е屡K、幻、不可重復讀
  •     read_committed--允許在并發事務已經提交后讀取??煞乐古K讀,但幻讀和不可重復讀仍可發生
  •     repeatable_read--對相同字段的多次讀取是一致的,除非數據被事務本身改變。可防止臟、不可重復讀,但幻讀仍可能發生
  •     serializable--完全服從acid的隔離級別,確保不發生臟、幻、不可重復讀。這在所有的隔離級別中是最慢的,它是典型的通過完全鎖定在事務中涉及的數據表來完成的

    其中,mysql默認采用repeatable_read隔離級別;oracle默認采用read_committed隔離級別

        事務傳播行為:(七種)

  •     required--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
  •     supports--支持當前事務,如果當前沒有事務,就以非事務方式執行。
  •     mandatory--支持當前事務,如果當前沒有事務,就拋出異常。
  •     requires_new--新建事務,如果當前存在事務,把當前事務掛起。
  •     not_supported--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  •     never--以非事務方式執行,如果當前存在事務,則拋出異常。
  •     nested--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與required類似的操作。擁有多個可以回滾的保存點,內部回滾不會對外部事務產生影響。只對datasourcetransactionmanager有效

  --transactionstatus 事務具體運行狀態

三、spring提供了以下方法控制事務

 

  a.編程式事務管理(基于java編程控制,很少使用)--見demo1包

       利用transactiontemplate將多個dao操作封裝起來

  *b.聲明式事務管理(基于spring的aop配置控制)

       -基于transactionproxyfactorybean的方式.(很少使用)--見demo2包

            需要為每個進行事務管理的類,配置一個transactionproxyfactorybean進行增強.

       -基于xml配置(經常使用)--見demo3包

            一旦配置好之后,類上不需要添加任何東西。

            如果action作為目標對象切入事務,需要在<aop:config>元素里添加proxy-target-class="true"屬性。原因是通知spring框架采用cglib技術生成具有事務管理功能的action類。

       -基于注解(配置簡單,經常使用)--見demo4包

            在applicationcontext.xml中開啟事務注解配置。(applicationcontext.xml中只需定義bean并追加以下元素)

?
1
2
3
4
<bean id="txmanager" class="...">
 <property name="sessionfactory">
 </property>
<tx:annotation-driven transaction-manager="txmanager"/>

            在目標組件類中使用@transactional,該標記可定義在類前或方法前。

四、示例(銀行轉賬)

 

        --編程式

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * @description:轉賬案例的dao層接口
 *
 */
public interface accountdao {
 /**
 * @param out
 * :轉出賬號
 * @param money
 * :轉賬金額
 */
 public void outmoney(string out, double money);
 
 /**
 *
 * @param in
 * :轉入賬號
 * @param money
 * :轉賬金額
 */
 public void inmoney(string in, double money);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * @description:轉賬案例的dao層實現類
 */
public class accountdaoimpl extends jdbcdaosupport implements accountdao {
 /**
 * @param out
 * :轉出賬號
 * @param money
 * :轉賬金額
 */
 @override
 public void outmoney(string out, double money) {
 string sql = "update account set money = money-? where name = ?";
 this.getjdbctemplate().update(sql, money, out);
 }
 /**
 * @param in
 * :轉入賬號
 * @param money
 * :轉賬金額
 */
 @override
 public void inmoney(string in, double money) {
 string sql = "update account set money = money+? where name = ?";
 this.getjdbctemplate().update(sql, money, in);
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * @description:轉賬案例的業務接口
 *
 */
public interface accountservice {
 /**
 * @param out :轉出賬號
 * @param in :轉入賬號
 * @param money :轉賬金額
 */
 public void transfer(string out,string in,double money);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
 * @description:轉賬案例的業務層實現類
 */
public class accountserviceimpl implements accountservice {
 // 注入轉賬的dao
 private accountdao accountdao;
 
 // 注入事務管理的模板
 private transactiontemplate transactiontemplate;
 
 /**
 * @param out
 * :轉出賬號
 * @param in
 * :轉入賬號
 * @param money
 * :轉賬金額
 */
 @override
 public void transfer(final string out, final string in, final double money) {
 
 // 未經事務控制的業務處理操作,如果過程中出異常,則導致前面的操作能完成,后面的不能,即轉賬成功但未收到轉賬款
 // accountdao.outmoney(out, money);
 // int i = 1/0;
 // accountdao.inmoney(in, money);
 
 transactiontemplate.execute(new transactioncallbackwithoutresult() {
 
 @override
 protected void dointransactionwithoutresult(
  transactionstatus transactionstatus) {
 accountdao.outmoney(out, money);
 // int i = 1 / 0;//事務控制,即出現異常,該段內代碼都執行失效
 accountdao.inmoney(in, money);
 }
 });
 }
 
 public void setaccountdao(accountdao accountdao) {
 this.accountdao = accountdao;
 }
 
 public void settransactiontemplate(transactiontemplate transactiontemplate) {
 this.transactiontemplate = transactiontemplate;
 }
}

applicationcontext1.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!-- 引入外部的屬性文件 -->
 <context:property-placeholder location="classpath:jdbc.properties"/>
 
 <!-- 配置c3p0連接池 -->
 <bean id="datasource" class="com.mchange.v2.c3p0.combopooleddatasource">
 <property name="driverclass" value="${jdbc.driverclass}" />
 <property name="jdbcurl" value="${jdbc.url}" />
 <property name="user" value="${jdbc.username}" />
 <property name="password" value="${jdbc.password}" />
 </bean>
 
 <!-- 配置業務層類 -->
 <bean id="accountservice" class="com.zs.spring.demo1.accountserviceimpl">
 <property name="accountdao" ref="accountdao" />
 <!-- 注入事務管理的模板 -->
 <property name="transactiontemplate" ref="transactiontemplate" />
 </bean>
 
 <!-- 配置dao類(簡化,會自動配置jdbctemplate) -->
 <bean id="accountdao" class="com.zs.spring.demo1.accountdaoimpl">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- 配置dao類(未簡化) -->
 <!-- <bean id="jdbctemplate" class="org.springframework.jdbc.core.jdbctemplate">
 <property name="datasource" ref="datasource" />
 </bean>
 <bean id="accountdao" class="com.zs.spring.demo1.accountdaoimpl">
 <property name="jdbctemplate" ref="jdbctemplate" />
 </bean> -->
 
 <!-- ==================================1.編程式的事務管理=============================================== -->
 <!-- 配置事務管理器 -->
 <bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- 配置事務管理的模板:spring為了簡化事務管理的代碼而提供的類 -->
 <bean id="transactiontemplate" class="org.springframework.transaction.support.transactiontemplate">
 <property name="transactionmanager" ref="transactionmanager"/>
 </bean>

測試:

?
1
2
3
4
5
6
7
8
9
10
11
@runwith(springjunit4classrunner.class)
@contextconfiguration("classpath:applicationcontext1.xml")
public class transactiontest {
 @resource(name = "accountservice")
 private accountservice accountservice;
 
 @test
 public void demo1() {
 accountservice.transfer("aaa", "bbb", 200d);
 }
}

    --基于transactionproxyfactorybean的方式

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class accountserviceimpl implements accountservice {
 // 注入轉賬的dao
 private accountdao accountdao;
 
 /**
 * @param out
 *  :轉出賬號
 * @param in
 *  :轉入賬號
 * @param money
 *  :轉賬金額
 */
 @override
 public void transfer(string out, string in, double money) {
 accountdao.outmoney(out, money);
 // int i = 1/0;
 accountdao.inmoney(in, money);
 }
 
 public void setaccountdao(accountdao accountdao) {
 this.accountdao = accountdao;
 }
}

applicationcontext2.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!-- 引入外部的屬性文件 -->
 <context:property-placeholder location="classpath:jdbc.properties"/>
 
 <!-- 配置c3p0連接池 -->
 <bean id="datasource" class="com.mchange.v2.c3p0.combopooleddatasource">
 <property name="driverclass" value="${jdbc.driverclass}" />
 <property name="jdbcurl" value="${jdbc.url}" />
 <property name="user" value="${jdbc.username}" />
 <property name="password" value="${jdbc.password}" />
 </bean>
 
 <!-- 配置業務層類 -->
 <bean id="accountservice" class="com.zs.spring.demo2.accountserviceimpl">
 <property name="accountdao" ref="accountdao" />
 </bean>
 
 <!-- 配置dao類(簡化,會自動配置jdbctemplate) -->
 <bean id="accountdao" class="com.zs.spring.demo2.accountdaoimpl">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- ==================================2.使用xml配置聲明式的事務管理(原始方式)=============================================== -->
 
 <!-- 配置事務管理器 -->
 <bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- 配置業務層的代理 -->
 <bean id="accountserviceproxy" class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
 <!-- 配置目標對象 -->
 <property name="target" ref="accountservice" />
 <!-- 注入事務管理器 -->
 <property name="transactionmanager" ref="transactionmanager"></property>
 <!-- 注入事務的屬性 -->
 <property name="transactionattributes">
  <props>
  <!--
   prop的格式:
   * propagation :事務的傳播行為
   * isotation :事務的隔離級別
   * readonly :只讀
   * -exception :發生哪些異常回滾事務
   * +exception :發生哪些異常不回滾事務
   -->
  <prop key="transfer">propagation_required</prop>
  <!-- <prop key="transfer">propagation_required,readonly</prop> -->
  <!-- <prop key="transfer">propagation_required,+java.lang.arithmeticexception</prop> -->
  </props>
 </property>
 </bean>

測試:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@runwith(springjunit4classrunner.class)
@contextconfiguration("classpath:applicationcontext2.xml")
public class transactiontest {
 /**
 * 一定要注入代理類:因為代理類進行增強的操作
 */
 // @resource(name="accountservice")
 @resource(name = "accountserviceproxy")
 private accountservice accountservice;
 
 @test
 public void demo1() {
 accountservice.transfer("aaa", "bbb", 200d);
 }
}

    --基于xml配置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class accountserviceimpl implements accountservice {
 // 注入轉賬的dao
 private accountdao accountdao;
 
 /**
 * @param out
 *  :轉出賬號
 * @param in
 *  :轉入賬號
 * @param money
 *  :轉賬金額
 */
 @override
 public void transfer(string out, string in, double money) {
 accountdao.outmoney(out, money);
 // int i = 1/0;
 accountdao.inmoney(in, money);
 
 }
 
 public void setaccountdao(accountdao accountdao) {
 this.accountdao = accountdao;
 }
}

applicationcontext3.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!-- 引入外部的屬性文件 -->
 <context:property-placeholder location="classpath:jdbc.properties"/>
 
 <!-- 配置c3p0連接池 -->
 <bean id="datasource" class="com.mchange.v2.c3p0.combopooleddatasource">
 <property name="driverclass" value="${jdbc.driverclass}" />
 <property name="jdbcurl" value="${jdbc.url}" />
 <property name="user" value="${jdbc.username}" />
 <property name="password" value="${jdbc.password}" />
 </bean>
 
 <!-- 配置業務層類 -->
 <bean id="accountservice" class="com.zs.spring.demo3.accountserviceimpl">
 <property name="accountdao" ref="accountdao" />
 </bean>
 
 <!-- 配置dao類(簡化,會自動配置jdbctemplate) -->
 <bean id="accountdao" class="com.zs.spring.demo3.accountdaoimpl">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- ==================================3.使用xml配置聲明式的事務管理,基于tx/aop=============================================== -->
 
 <!-- 配置事務管理器 -->
 <bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- 配置事務的通知 -->
 <tx:advice id="txadvice" transaction-manager="transactionmanager">
 <tx:attributes>
  <!--
  propagation :事務傳播行為
  isolation :事務的隔離級別
  read-only :只讀
  rollback-for:發生哪些異?;貪L
  no-rollback-for :發生哪些異常不回滾
  timeout :過期信息
  -->
  <tx:method name="transfer" propagation="required"/>
 </tx:attributes>
 </tx:advice>
 
 <!-- 配置切面 -->
 <aop:config>
 <!-- 配置切入點 -->
 <aop:pointcut expression="execution(* com.zs.spring.demo3.accountservice+.*(..))" id="pointcut1"/>
 <!-- 配置切面 -->
 <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
 </aop:config>

測試:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * @description:spring的聲明式事務管理的方式二:基于aspectj的xml方式的配置
 */
@runwith(springjunit4classrunner.class)
@contextconfiguration("classpath:applicationcontext3.xml")
public class transactiontest {
 /**
 * 一定要注入代理類:因為代理類進行增強的操作
 */
 @resource(name = "accountservice")
 private accountservice accountservice;
 
 @test
 public void demo1() {
 accountservice.transfer("aaa", "bbb", 200d);
 }
}

    --基于注解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * @transactional中的的屬性 propagation :事務的傳播行為 isolation :事務的隔離級別 readonly :只讀
 *   rollbackfor :發生哪些異?;貪L norollbackfor :發生哪些異常不回滾
 *   rollbackforclassname 根據異常類名回滾
 */
@transactional(propagation = propagation.required, isolation = isolation.default, readonly = false)
public class accountserviceimpl implements accountservice {
 // 注入轉賬的dao
 private accountdao accountdao;
 
 /**
 * @param out
 *  :轉出賬號
 * @param in
 *  :轉入賬號
 * @param money
 *  :轉賬金額
 */
 @override
 public void transfer(string out, string in, double money) {
 accountdao.outmoney(out, money);
 // int i = 1/0;
 accountdao.inmoney(in, money);
 }
 
 public void setaccountdao(accountdao accountdao) {
 this.accountdao = accountdao;
 }
}

applicationcontext4.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- 引入外部的屬性文件 -->
 <context:property-placeholder location="classpath:jdbc.properties"/>
 
 <!-- 配置c3p0連接池 -->
 <bean id="datasource" class="com.mchange.v2.c3p0.combopooleddatasource">
 <property name="driverclass" value="${jdbc.driverclass}" />
 <property name="jdbcurl" value="${jdbc.url}" />
 <property name="user" value="${jdbc.username}" />
 <property name="password" value="${jdbc.password}" />
 </bean>
 
 <!-- 配置業務層類 -->
 <bean id="accountservice" class="com.zs.spring.demo4.accountserviceimpl">
 <property name="accountdao" ref="accountdao" />
 </bean>
 
 <!-- 配置dao類(簡化,會自動配置jdbctemplate) -->
 <bean id="accountdao" class="com.zs.spring.demo4.accountdaoimpl">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- ==================================4.使用注解配置聲明式事務============================================ -->
 
 <!-- 配置事務管理器 -->
 <bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
 <property name="datasource" ref="datasource" />
 </bean>
 
 <!-- 開啟注解事務 -->
 <tx:annotation-driven transaction-manager="transactionmanager"/>

測試:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@runwith(springjunit4classrunner.class)
@contextconfiguration("classpath:applicationcontext4.xml")
public class transactiontest {
 /**
 * 一定要注入代理類:因為代理類進行增強的操作
 */
 @resource(name = "accountservice")
 private accountservice accountservice;
 
 @test
 public void demo1() {
 accountservice.transfer("aaa", "bbb", 200d);
 }
}

具體代碼和數據庫文件參考項目完整代碼:

spring-transaction.rar

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://blog.csdn.net/daijin888888/article/details/51822257

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 第一区免费在线观看 | 日韩深夜视频 | 一级成人黄色片 | 羞羞的视频免费在线观看 | 国产在线导航 | 成人激情视频网站 | 性少妇chinesevideo | 伊人yinren22综合网色 | 亚洲国产高清视频 | 午夜影院在线免费观看 | 最新福利在线 | 国产一级毛片国语版 | 黄色网www | 欧美一级不卡视频 | 亚洲一区二区观看播放 | 成人福利免费在线观看 | 羞羞视频免费网站 | 国产在线观看91一区二区三区 | 日本羞羞的午夜电视剧 | www.精品一区 | 欧美顶级毛片在线播放小说 | 欧洲黄色一级视频 | 久草网在线 | 亚州欧美视频 | 国产男女爽爽爽爽爽免费视频 | 做羞羞视频 | 久久久日韩精品一区二区 | 国产一级毛片在线看 | 91短视频在线观看 | 国产亚洲区| 久久久久久久久久美女 | 毛片视频播放 | 快播av在线 | h久久 | 久久久在线免费观看 | 久久久三级免费电影 | 在线免费观看精品 | 毛片在线视频观看 | 99国产精品白浆在线观看免费 | 一区二区久久精品66国产精品 | 深夜免费福利视频 |