Spring 使用註解對事務控制詳解與實例

1.什麼是事務

一榮俱榮,一損俱損,很多複雜的操作我們可以把它看成是一個整體,要麼同時成功,要麼同時失敗。


事務的四個特徵ACID:

原子性(Atomic):表示組成一個事務的多個數據庫的操作的不可分割的單元,只有所有的操作成功纔算成功,整個事務提交,其中任何一個操作失敗了都是導致整個所有操作失敗,事務會回滾。

一致性(Consistentcy):事務操作成功後,數據庫所處的狀態和業務規則一致。如果A賬戶給B賬戶匯100,A賬戶減去100,B加上100,兩個賬戶的總額是不變的。
隔離性(islation):在多個數據庫的操作相同的數據併發時,不同的事務有自己的數據空間,事務與事務之間不受干擾(不是絕對的)。干擾程度受數據庫或者操作事務的隔離級別來決定,隔離級別越高,干擾就越低,數據的一致性越好,併發性就越差。
持久性(Druability):一旦事務提交成功,數據就被持久化到數據庫,不可以回滾。

 

 

2.spring使用註解對事務的控制

  Spring 事務管理有兩種方式:編程式事務管理聲明式事務管理
    編程式事務管理通過TransactionTemplate手動管理事務,在實際應用中很少使用,我們來重點學習聲明式事務管理
    聲明式事務管理有三種實現方式:基於TransactionProxyFactoryBean的方式基於AspectJ的XML方式基於註解的方式
  

  1. 新建一個java工程——導入spring 和事務管理所需要的jar   ——然後選擇全部jar 右鍵Build path   ——最後如圖           (我的java版本jre是1.8)                             Spring 事務管理所需要的jar包  鏈接如下:https://www.cnblogs.com/ysource/p/12956273.html  jar在文章中

 

 

2.在src目錄下新建5個包   如圖

    dao :數據連接層,主要用於存放對數據進行操作的類

    model:模型層,主要用於存放實體類

    service:服務層,主要用於對數據連接層進行操作的一些服務類。

    util:工具類,主要用於存儲工具方法

    test:用於測試類

 

3.在dao數據連接層,建立裏與數據庫操作的類與對應的接口 (Order 訂單 ,detail訂單明細)

 3.1 定義detailDao接口 代碼如下:

 1 package com.spring.dao;
 2 
 3 import com.spring.model.Detail;
 4 import com.spring.model.Order;
 5 
 6 public interface detailDao {
 7     //保存訂單明細
 8     public void saveDetail(Detail detail);
 9     
10     
11     
12 }

  3.2  定義OrderDao接口 代碼如下:

1 package com.spring.dao;
 2 
 3 import com.spring.model.Order;
 4 
 5 public interface OrderDao {
 6     //保存訂單 
 7     public void saveOrder(Order order);
 8     
 9     
10     
11 }

  3.3 實現以上接口

detailDaoImp 代碼如下:
 1 package com.spring.dao;
 2 
 3 import javax.sql.DataSource;
 4 
 5 import org.springframework.jdbc.core.JdbcTemplate;
 6 
 7 import com.spring.model.Detail;
 8 import com.spring.model.Order;
 9 
10 public class detailDaoImp implements detailDao {
11 
12     private DataSource dataSource;
13     private JdbcTemplate jdbcTemplate;
14 
15     public void setDataSource(DataSource dataSource) {
16         this.dataSource = dataSource;
17         this.jdbcTemplate = new JdbcTemplate(dataSource);
18     }
19     //保存訂單明細
20     public void saveDetail(Detail detail) {
21         String SQL = "insert into t_detail values(null,?,?,?))";
22         jdbcTemplate.update(SQL, new Object[] { detail.getItemName(),detail.getQuantity(),detail.getOrderId() });
23         System.out.println("Insert detail success!");
24     }
25 
26 }

  

 

     OrderDaoImp代碼如下:

package com.spring.dao;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.spring.model.Order;

public class OrderDaoImp implements OrderDao {

    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    //插入訂單
    public void saveOrder(Order order) {
        String SQL = "insert into t_order values (null,?)";
        System.out.println(SQL);
        System.out.println(order.getTotal_price());
        jdbcTemplate.update(SQL, new Object[]{order.getTotal_price()});
        System.out.println("Insert order success!");
    }

}

 

4.在model層中新建兩個實體類  (Order訂單類,detail訂單明細類)

  Order訂單類代碼如下:

 1 package com.spring.model;
 2 
 3 /*
 4  * 訂單表
 5  */
 6 public class Order {
 7     //訂單編號
 8     private Integer order_id;
 9     //訂單總金額
10     private Integer total_price;
11     public Integer getOrder_id() {
12         return order_id;
13     }
14     public void setOrder_id(Integer order_id) {
15         this.order_id = order_id;
16     }
17     public Integer getTotal_price() {
18         return total_price;
19     }
20     public void setTotal_price(Integer total_price) {
21         this.total_price = total_price;
22     }
23 }

 

 detail訂單明細類代碼如下:

 1 package com.spring.model;
 2 
 3 /**
 4  * 商品明細表
 5  * @author Administrator
 6  *
 7  */
 8 public class Detail {
 9     //ID
10     private Integer detailId;
11     //外鍵  暫時可以忽略
12     private Integer orderId;
13     public Integer getDetailId() {
14         return detailId;
15     }
16     public void setDetailId(Integer detailId) {
17         this.detailId = detailId;
18     }
19     public Integer getOrderId() {
20         return orderId;
21     }
22     public void setOrderId(Integer orderId) {
23         this.orderId = orderId;
24     }
25     public Integer getQuantity() {
26         return quantity;
27     }
28     public void setQuantity(Integer quantity) {
29         this.quantity = quantity;
30     }
31     public String getItemName() {
32         return itemName;
33     }
34     public void setItemName(String itemName) {
35         this.itemName = itemName;
36     }
37     //商品數量
38     private Integer quantity;
39     //商品數量
40     private String itemName;
41 
42 }

5.在service中定義一個接口並且實現它

    OrderService代碼如下:

1 package com.spring.service;
2 
3 import com.spring.model.Detail;
4 import com.spring.model.Order;
5 
6 public interface OrderService {
7     //插入訂單和訂單明細
8     public void saveOrderAndDetail(Order order,Detail detail);
9 }

 

  OrderServiceImp代碼如下:

 1 package com.spring.service;
 2 
 3 import org.springframework.transaction.annotation.Transactional;
 4 
 5 import com.spring.dao.OrderDaoImp;
 6 import com.spring.dao.detailDaoImp;
 7 import com.spring.model.Detail;
 8 import com.spring.model.Order;
 9 
10 /**
11  * 服務層 使用註解來實現事務管理
12  * 
13  * @author Administrator
14  *
15  */
16 
17 public class OrderServiceImp implements OrderService {
18     // 注入兩個對象
19     public OrderDaoImp OrderDaoImp;
20 
21     public detailDaoImp detailDaoImp;
22 
23     @Transactional
24     @Override
25     // 如果加上@Transaction時,方法執行有異常,整個事務數據都會回滾,數據庫中不會存在有數據。
26     public void saveOrderAndDetail(Order order, Detail detail) {
27         OrderDaoImp.saveOrder(order);
28         /**
29          * 如果不加@transaction時有異常存在,OrderDaoImp.saveOrder(order)方法將會執行。
30          * 但detailDaoImp.saveDetail(detail)不會執行
31          **/
32         int i = 100 / 0;
33         detailDaoImp.saveDetail(detail);
34 
35     }
36 
37     public OrderDaoImp getOrderDaoImp() {
38         return OrderDaoImp;
39     }
40 
41     public void setOrderDaoImp(OrderDaoImp orderDaoImp) {
42         OrderDaoImp = orderDaoImp;
43     }
44 
45     public detailDaoImp getDetailDaoImp() {
46         return detailDaoImp;
47     }
48 
49     public void setDetailDaoImp(detailDaoImp detailDaoImp) {
50         this.detailDaoImp = detailDaoImp;
51     }
52 
53 }

 

6.在util包中定義一個通知方法類

 1 package com.spring.util;
 2 
 3 public class SeizedAdvice {
 4     /**
 5      * 定義通知
 6      */
 7 
 8     public void beforeAdvice(){
 9         System.out.println("——————我是前置通知————————");
10         
11     }
12     public void afterAdvice(){
13         System.out.println("------我是後置通知-------");
14         
15     }
16     public void afterReturningAdvice(Object object){
17         System.out.println("————————我是返回後通知——————————"+object.toString());
18         
19     }
20     public void afterThrowingAdvice(IllegalAccessError illegalAccessError){
21         System.out.println("--------我是異常返回異常返回通知---------"+illegalAccessError.toString());
22     
23         
24     }
25     
26     
27     
28 }

7.在test中定義個測試類,用於測試

 1 package com.test;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 import com.spring.model.Detail;
 7 import com.spring.model.Order;
 8 import com.spring.service.OrderServiceImp;
 9 
10 public class Test {
11 
12     public static void main(String[] args) {
13         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
14         OrderServiceImp imp=(OrderServiceImp)applicationContext.getBean("OrderServiceImp");
15         
16         Order order=new Order();
17         order.setTotal_price(699);
18         Detail detail=new Detail();
19         detail.setItemName("牙刷");
20         detail.setQuantity(3);
21         detail.setOrderId(4);
22         imp.saveOrderAndDetail(order,detail);
23         
24     }
25 }

 

8.最後就是我們的配置文件和數據庫中的兩張表

   Spring  bean.xml代碼如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
 4     xmlns:aop="http://www.springframework.org/schema/aop"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 
 7    http://www.springframework.org/schema/tx
 8    http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
 9    http://www.springframework.org/schema/aop
10    http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
11     <!-- 定義數據源 -->
12     <bean id="dataSource"
13         class="org.springframework.jdbc.datasource.DriverManagerDataSource">
14         <property name="driverClassName" value="com.mysql.jdbc.Driver" />
15         <property name="url" value="jdbc:mysql://localhost:3306/jerry" />
16         <property name="username" value="root" />
17         <property name="password" value="1234" />
18     </bean>
19 
20 
21 
22     <!-- 事務管理方式註解驅動 -->
23     <tx:annotation-driven transaction-manager="transactionManager" />
24 
25     <!-- 配置數據   proxy-target-class屬性值決定是基於接口的還是基於類的代理被創建。
26         如果proxy-target-class 屬性值被設置爲true,那麼基於類的代理將起作用-->
27     <aop:config proxy-target-class="true">
28         <!-- 切 面-->
29         <aop:aspect id="myAspect" ref="SeizedAdvice">
30             <!-- 切 點-->
31             <aop:pointcut expression="execution(* com.spring.service.OrderServiceImp.*(..))"
32                 id="myPointCut" />
33             <aop:before pointcut-ref="myPointCut" method="beforeAdvice" />
34             <aop:after pointcut-ref="myPointCut" method="afterAdvice" />
35         </aop:aspect>
36     </aop:config>
37 
38 
39     <!-- 定義事務管理器 -->
40     <bean id="transactionManager"
41         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
42         <property name="dataSource" ref="dataSource" />
43     </bean>
44 
45     <!-- 定義我們所需的bean -->
46     <bean id="SeizedAdvice" class="com.spring.util.SeizedAdvice"></bean>
47 
48     <bean id="OrderServiceImp" class="com.spring.service.OrderServiceImp">
49         <property name="detailDaoImp" ref="detailDaoImp"></property>
50         <property name="OrderDaoImp" ref="OrderDaoImp"></property>
51     </bean>
52 
53     <bean id="detailDaoImp" class="com.spring.dao.detailDaoImp">
54         <property name="dataSource" ref="dataSource" />
55     </bean>
56 
57     <bean id="OrderDaoImp" class="com.spring.dao.OrderDaoImp">
58         <property name="dataSource" ref="dataSource" />
59     </bean>
60 
61 </beans>

 9. 數據庫設計

detail(訂單明細表  detail_id   訂單明細ID,item_name  商品名稱,quantity  訂單數量  ,order_id  外鍵   暫時不用管這個屬性

 

Order(訂單表,order_id   訂單id,total_price   總金額)

 

 10. 沒有加@transaction測試如下:

 

這就會造成數據錯誤,不符合事務管理要求。加上@transaction再次測試如下圖;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章