zoukankan      html  css  js  c++  java
  • 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再次测试如下图;

  • 相关阅读:
    System.nanoTime()的使用
    只为高效、流畅开发 —— 码云企业版 3.0 倾情上线
    不自律的人,下场都很惨
    刘德:小米已投89家生态链企业 有品要做百亿电商平台(本质上是是利用了小米的大火炉的余热,但也有反向的正面作用)
    英雄无敌手游(战争纪元云中城,还可以骑龙,绝美)
    openFrameworks 是一个旨在助力你进行开创性工作的开源 C++ 工具箱(是很多其它类库的组合)
    Core开发-MVC 使用dotnet 命令创建Controller和View
    Ant Table组件
    web性能优化
    scss + react + webpack + es6
  • 原文地址:https://www.cnblogs.com/ysource/p/12956273.html
Copyright © 2011-2022 走看看