• spring来了-06-事务控制


    概述

      编程式事务控制

        自己手动控制事务,就叫做编程式事务控制。

        Jdbc代码:

          Conn.setAutoCommite(false);  // 设置手动控制事务

        Hibernate代码:

          Session.beginTransaction();    // 开启一个事务

        【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】

        (比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)

    spring提供的事务控制

      声明式事务控制

        Spring提供了对事务的管理, 这个就叫声明式事务管理。

        Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务  控制的最大程度的解耦。

        Spring声明式事务管理,核心实现就是基于Aop。

        【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】

        (因为aop拦截的是方法。)

        Spring声明式事务管理器类:

          Jdbc技术:DataSourceTransactionManager

          Hibernate技术:HibernateTransactionManager

      1 package cn.fuyi.a_tx;
      2 
      3 public class Dept {
      4 
      5     private Integer deptId;
      6     private String dname;
      7     public Integer getDeptId() {
      8         return deptId;
      9     }
     10     public void setDeptId(Integer deptId) {
     11         this.deptId = deptId;
     12     }
     13     public String getDname() {
     14         return dname;
     15     }
     16     public void setDname(String dname) {
     17         this.dname = dname;
     18     }
     19     
     20 }
     21 
     22 package cn.fuyi.a_tx;
     23 
     24 import org.springframework.jdbc.core.JdbcTemplate;
     25 
     26 public class DeptDao {
     27 
     28     private JdbcTemplate jdbcTemplate;
     29     public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
     30         this.jdbcTemplate = jdbcTemplate;
     31     }
     32     
     33     public void save(Dept dept) {
     34         String sql = "insert into dept(dname) values(?)";
     35         jdbcTemplate.update(sql, dept.getDname());
     36     }
     37 }
     38 
     39 package cn.fuyi.a_tx;
     40 
     41 public class DeptService {
     42 
     43     private DeptDao deptDao;
     44     public void setDeptDao(DeptDao deptDao) {
     45         this.deptDao = deptDao;
     46     }
     47     
     48     public void save(Dept dept) {
     49         deptDao.save(dept);
     50         int i = 1/0;
     51         deptDao.save(dept);
     52         
     53     }
     54 }
     55 
     56 <?xml version="1.0" encoding="UTF-8"?>
     57 <beans xmlns="http://www.springframework.org/schema/beans"
     58     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     59     xmlns:p="http://www.springframework.org/schema/p"
     60     xmlns:context="http://www.springframework.org/schema/context"
     61     xmlns:aop="http://www.springframework.org/schema/aop"
     62     xmlns:tx="http://www.springframework.org/schema/tx"
     63     xsi:schemaLocation="
     64         http://www.springframework.org/schema/beans
     65         http://www.springframework.org/schema/beans/spring-beans.xsd
     66         http://www.springframework.org/schema/context
     67         http://www.springframework.org/schema/context/spring-context.xsd
     68         http://www.springframework.org/schema/aop
     69         http://www.springframework.org/schema/aop/spring-aop.xsd
     70         http://www.springframework.org/schema/tx
     71          http://www.springframework.org/schema/tx/spring-tx.xsd">
     72 
     73     <!-- dataSource配置 -->
     74     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
     75         <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
     76         <property name="jdbcUrl" value="jdbc:mysql:///mydb"></property>
     77         <property name="user" value="root"></property>
     78         <property name="password" value="950613"></property>
     79         <property name="initialPoolSize" value="4"></property>
     80         <property name="maxPoolSize" value="9"></property>
     81         <property name="maxStatements" value="100"></property>
     82         <property name="acquireIncrement" value="2"></property>
     83     </bean>
     84     
     85     <!-- JdbcTemplate工具类实例 -->
     86     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
     87         <property name="dataSource" ref="dataSource"></property>
     88     </bean>
     89     
     90     <!-- dao实例 -->
     91     <bean id="deptDao" class="cn.fuyi.a_tx.DeptDao">
     92         <property name="jdbcTemplate" ref="jdbcTemplate"></property>
     93     </bean>
     94     
     95     <!-- service实例 -->
     96     <bean id="deptService" class="cn.fuyi.a_tx.DeptService">
     97         <property name="deptDao" ref="deptDao"></property>
     98     </bean>
     99     
    100     
    101     <!-- spring的声明式事务配置 -->
    102     <!-- 1.配置事务管理器类 -->
    103     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    104         <property name="dataSource" ref="dataSource"></property>
    105     </bean>
    106     
    107     <!-- 2.配置事务增强(如何管理事务?) -->
    108     <tx:advice id="txAdvice" transaction-manager="transactionManager">
    109         <tx:attributes>
    110             <tx:method name="*save*" read-only="false" isolation="DEFAULT" propagation="REQUIRED"/>
    111             <tx:method name="*find*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"/>
    112             <tx:method name="*get*" read-only="true" isolation="DEFAULT" propagation="REQUIRED"/>
    113         </tx:attributes>
    114     </tx:advice>
    115 
    116     <!-- 3.AOP配置:拦截哪些方法(切入点表达式 + 应用上面的事务增强配置) -->
    117     <aop:config>
    118         <aop:pointcut expression="execution(* cn.fuyi.a_tx.DeptService.*(..))" id="pt"/>
    119         <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    120     </aop:config>
    121         
    122 </beans>
    123 
    124 package cn.fuyi.a_tx;
    125 
    126 import static org.junit.Assert.*;
    127 
    128 import org.junit.Test;
    129 import org.springframework.context.ApplicationContext;
    130 import org.springframework.context.support.ClassPathXmlApplicationContext;
    131 
    132 public class App {
    133 
    134     private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/fuyi/a_tx/beans.xml");
    135     
    136     @Test
    137     public void testTx1() throws Exception {
    138         DeptService ds = (DeptService) ac.getBean("deptService");
    139         Dept dept = new Dept();
    140         dept.setDname("哈2哈");
    141         ds.save(dept);
    142     }
    143 }
    144 
    145 /**Output
    146     
    147      数据库回滚
    148  
    149 */
    View Code

      注解方式实现

        使用注解实现Spring的声明式事务管理,更加简单!

        步骤:

      1) 必须引入Aop相关的jar文件

      2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类

      3)在需要添加事务控制的地方,写上: @Transactional

       @Transactional注解:

      1)应用事务的注解

      2)定义到方法上: 当前方法应用spring的声明式事务

      3)定义到类上:   当前类的所有的方法都应用Spring声明式事务管理;

      4)定义到父类上: 当执行父类的方法时候应用事务。

     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" 
     4     xmlns:p="http://www.springframework.org/schema/p"
     5     xmlns:context="http://www.springframework.org/schema/context"
     6     xmlns:aop="http://www.springframework.org/schema/aop"
     7     xmlns:tx="http://www.springframework.org/schema/tx"
     8     xsi:schemaLocation="http://www.springframework.org/schema/beans
     9          http://www.springframework.org/schema/beans/spring-beans.xsd
    10           http://www.springframework.org/schema/context
    11          http://www.springframework.org/schema/context/spring-context.xsd
    12          http://www.springframework.org/schema/aop
    13          http://www.springframework.org/schema/aop/spring-aop.xsd
    14          http://www.springframework.org/schema/tx
    15           http://www.springframework.org/schema/tx/spring-tx.xsd">
    16 
    17     
    18     <!-- 1. 数据源对象: C3P0连接池 -->
    19     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    20         <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    21         <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
    22         <property name="user" value="root"></property>
    23         <property name="password" value="root"></property>
    24         <property name="initialPoolSize" value="3"></property>
    25         <property name="maxPoolSize" value="10"></property>
    26         <property name="maxStatements" value="100"></property>
    27         <property name="acquireIncrement" value="2"></property>
    28     </bean>
    29     
    30     <!-- 2. JdbcTemplate工具类实例 -->
    31     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    32         <property name="dataSource" ref="dataSource"></property>
    33     </bean>
    34     
    35     <!-- 事务管理器类 -->
    36     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    37         <property name="dataSource" ref="dataSource"></property>
    38     </bean>
    39     
    40     <!-- 开启注解扫描 -->
    41     <context:component-scan base-package="cn.itcast.b_anno"></context:component-scan>
    42     
    43     <!-- 注解方式实现事务: 指定注解方式实现事务 -->
    44     <tx:annotation-driven transaction-manager="txManager"/>
    45 </beans>     
    View Code

    事务属性

     1 @Transactional(
     2             readOnly = false,  // 读写事务
     3             timeout = -1,       // 事务的超时时间不限制
     4             noRollbackFor = ArithmeticException.class,  // 遇到数学异常不回滚
     5             isolation = Isolation.DEFAULT,              // 事务的隔离级别,数据库的默认
     6             propagation = Propagation.REQUIRED            // 事务的传播行为
     7     )
     8     public void save(Dept dept){
     9         deptDao.save(dept);
    10         int i = 1/0;
    11         deptDao.save(dept);
    12     }

    事务传播行为:

      Propagation.REQUIRED

        指定当前的方法必须在事务的环境下执行;

        如果当前运行的方法,已经存在事务, 就会加入当前的事务;

      Propagation.REQUIRED_NEW

        指定当前的方法必须在事务的环境下执行;

        如果当前运行的方法,已经存在事务:  事务会挂起; 会始终开启一个新的事务,执行完后;  刚才挂起的事务才继续运行。

      举例:

     1 1.Propagation.REQUIRED  
     2 Class Log{
     3     @Propagation.REQUIRED  
     4     insertLog();  
     5 }
     6 
     7 Class DeptDao{
     8     @Propagation.REQUIRED
     9     Void  saveDept(){
    10         insertLog();    // 加入当前事务
    11         .. 出现异常, 会回滚
    12         saveDept();
    13     }
    14 }
    15 
    16 2.Propagation.REQUIRED_NEW  
    17 Class Log{
    18     @Propagation.REQUIRED_NEW  
    19     insertLog();  
    20 }
    21 
    22 Class DeptDao{
    23     @Propagation.REQUIRED
    24     Void  saveDept(){
    25         insertLog();    // 始终开启事务
    26         .. 异常, 日志不会回滚
    27         saveDept();
    28     }
    29 }

      测试:

     1 package cn.fuyi.a_tx;
     2 
     3 import javax.annotation.Resource;
     4 
     5 import org.springframework.jdbc.core.JdbcTemplate;
     6 import org.springframework.stereotype.Repository;
     7 import org.springframework.transaction.annotation.Propagation;
     8 import org.springframework.transaction.annotation.Transactional;
     9 
    10 @Repository
    11 public class LogDao {
    12 
    13     @Resource
    14     private JdbcTemplate jdbcTemplate;
    15     
    16     @Transactional(propagation=Propagation.REQUIRES_NEW)
    17     public void insertLog() {
    18         String sql = "insert into log_ values('在保存dept。。。')";
    19         jdbcTemplate.update(sql);
    20     }
    21 }
    22 
    23 package cn.fuyi.a_tx;
    24 
    25 import javax.annotation.Resource;
    26 
    27 import org.springframework.stereotype.Service;
    28 import org.springframework.transaction.annotation.Propagation;
    29 import org.springframework.transaction.annotation.Transactional;
    30 
    31 @Service("deptService")
    32 public class DeptService {
    33 
    34     @Resource(name="deptDao")
    35     private DeptDao deptDao;
    36     
    37     @Resource(name="logDao")
    38     private LogDao logDao;
    39     
    40     
    41     @Transactional(
    42             propagation=Propagation.REQUIRED
    43         )
    44     public void save(Dept dept) {
    45         logDao.insertLog();
    46         int i = 1/0;
    47         deptDao.save(dept);
    48     }
    49 }

     

  • 相关阅读:
    JavaScript基本语法2
    JavaScript的基本语法
    在网页中加入神奇的效果
    一个由表单构成的页面
    进程理论要点
    TCP大文件上传与UDP协议
    socket编程相关阐述
    网络编程
    魔法方法
    元类与单例解析
  • 原文地址:https://www.cnblogs.com/fuyiming/p/5832150.html
Copyright © 2020-2023  润新知