Fork me on GitHub

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

 

 

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再次测试如下图;

posted @ 2020-05-25 16:25  云源  阅读(1965)  评论(0编辑  收藏  举报
湖南云源网络科技有限公司 www. ysource.cn 版权所有   ICP证:湘ICP备18004366号
  邮箱:2536201485@qq.com   CSDN博客地址:https://blog.csdn.net/qq_32885621 有事您Q我