Spring的相关配置

基本概念

  1. IOC:(Inverse of Control)控制反转     将对象的创建权反转(交给)Spring
  2. DI:(Dependency Injection)依赖注入    前提必须得有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来
  3. AOP:(Aspect Oriented Programming)面向切面编程    通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。   AOP是OOP(面相对象编程)的扩展和延伸,解决AOP开发中遇到的一些问题.

XML提示的配置

​ Scheme的配置

XML的schema配置

Bean的相关配置(XML)

  • 标签的id和name的配置    大部分情况下作用相同

    • id :使用了约束中的唯一约束.里面不能出现特殊字符
  • name: 没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现的),name里面可以出现特殊字符
  • Bean的生命周期的配置

    init-method :Bean被初始化的时候执行的方法

    destroy :Bean被销毁的时候执行的方法 执行条件(1.Bean是单例创建的(默认就是单例创建的) 2.工厂关闭) 如果是多例模式下不知道销毁哪个所以就不会销毁。

  • Bean的作用范围的配置

    • scope :Bean的作用范围

      1. singleton :默认的,Spring会采用单例模式来创建这个对象(在创建容器读取配置文件的时候立即创建对象,立即加载)

      2. prototype :多例模式(当真正调用对象的时候再创建对象,延迟加载,因为不知道创建多少个对象)

      3. request :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。

      4. session :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。

      5. globalsession:应用在web项目中,作用于集群环境下的会话范围,必须在porlet(集群)环境下使用,如果没有这种环境,相当于session。

开发中常用的就是singleton和prototype

  • Spring的属性注入(给Bean中的属性设置值)的方式

    • 构造方法的方式属性注入:

      • 1
        2
        3
        4
        5
        6
           <!-- Spring属性注入的方式 -->
        <!-- 构造方法的方式 -->
        <bean id="car" class="spring.demo3.Car">
        <constructor-arg name="name" value="宝马"/>
        <constructor-arg name="price" value="800000"/>
        </bean>
  • Set方法的方式的属性注入:

    • 1
      2
      3
      4
      5
      <!-- set方法的方式 -->        
      <bean id="car2" class="spring.demo3.Car2">
      <property name="name" value="奔驰"/>
      <property name="price" value="1000000"/>
      </bean>
    • 1
      2
      3
      4
      5
      6
      <!-- set方法注入对象类型的属性 -->
      <bean id="employee" class="spring.demo3.Employee">
      <property name="name" value="涛哥"/>
      <!-- value:设置普通属性类型的值 ref:用来设置其他类的id和name -->
      <property name="car2" ref="car2"/>
      </bean>
  • P名称空间的属性注入(Spring2.0以后)

    • 通过引入p名称空间完成属性的注入
      • 写法:
        1. 普通属性: p:属性名=”值”
  1. 对象属性: p:属性名-ref=”值”

        引入p名称空间  
    
    
    1
    xmlns:p="http://www.springframework.org/schema/p"
1
2
3
4
   <!-- 改为p名称空间的方式 -->
<bean id="car2" class="spring.demo3.Car2" p:name="奇瑞qq" p:price="30000"></bean>
<!-- p名称空间的方式来注入对象类型 -->
<bean id="employee" class="spring.demo3.Employee" p:name="王东" p:car2-ref="car2"></bean>
  • SpEL的属性注入(Spring3.0以后)

    • SpEL(Spring Expression Language) :Spring的表达式语言

    • 语法:   #{SpEL}

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
        
      <!-- SpEL方式属性注入 -->
      <bean id="carInfo" class="spring.demo3.CarInfo">

      </bean>
      <bean id="car2" class="spring.demo3.Car2">
      <property name="name" value="#{carInfo.name}"></property>
      <property name="price" value="#{carInfo.calculatorPrice()}"></property>
      </bean>

      <bean id="employee" class="spring.demo3.Employee">
      <property name="name" value="#{'张三'}"></property>
      <property name="car2" value="#{car2}"></property>
      </bean>
  • 集合类型属性的注入

    • 数组类型,list类型,set类型,map类型

    • 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
          
      <!-- Spring的集合属性的注入 -->

      <bean id="collectionBean" class="spring.demo4.CollectionBean">
      <!-- 注入数组类型 -->
      <property name="arrs" >
      <list>
      <!-- <ref/> 引入对象类型 -->
      <value>王东</value> <!-- 引入一般类型 -->
      <value>赵红</value>
      <value>李冠希</value>
      </list>
      </property>
      <!-- 注入List集合类型 -->
      <property name="list" >
      <list>
      <!-- <ref/> 引入对象类型 -->
      <value>小明</value> <!-- 引入一般类型 -->
      <value>小红</value>
      <value>小狗</value>
      </list>
      </property>

      <!-- 注入Set集合类型-->
      <property name="set" >
      <set>
      <!-- <ref/> 引入对象类型 -->
      <value>aaa</value> <!-- 引入一般类型 -->
      <value>bbb</value>
      <value>ccc</value>
      </set>
      </property>

      <!-- 注入Map集合 -->
      <property name="map">
      <map>
      <entry key="aaa" value="111"/>
      <entry key="bbb" value="222"/>
      <entry key="ccc" value="333"/>
      </map>
      </property>

      </bean>

Spring分模块开发的配置

  • 在加载配置文件的时候,加载多个

    • 1
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
  • 在一个配置文件中引入多个配置文件

    • 1
      2
      <!-- 引入多个配置文件 -->
      <import resource="applicationContext2.xml"/>

Spring 的IOC的注解的详解(注解)

1
2
<!-- 使用IOC的注解开发,配置组件扫描(要在哪些包下的类使用IOC的注解) -->
<context:component-scan base-package="spring"></context:component-scan>
  • @Component:组件

    • 修饰一个类,将这个类交给Spring管理相当于

      <bean id="orderDao" class="spring.demo1.OrderDao"></bean>

    • 这个注解有三个衍生注解(功能类似),修饰类

      • Controller: web层
      • Service: servcice层
      • Repository: dao层
  • 属性注入的注解
    • 普通属性:
      • @Value:设置普通属性的值
    • 对象类型属性:
      • @Autowired:设置对象类型的属性的值,但是是按照类型完成属性的注入.
        • 我们习惯是按照名称完成属性的注入,必须让@AutoWired和@Qualifier(value=”id”)一起使用完成按照名称属性注入.
      • @Resource(name=”id”):完成对象类型的属性的注入,按照名称完成属性注入.
  • Bean的其他的注解

    • 生命周期相关的注解
      • @PostConstruct:初始化方法
      • @PreDestory: 销毁方法
    • Bean作用范围的注解

      • @Scope
      1. singleton :默认的,Spring会采用单例模式来创建这个对象

      2. prototype :多例模式

      3. request :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。

      4. session :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。

      5. globalsession:应用在web项目中,必须在porlet环境下使用,如果没有这种环境,相当于session。

开发中常用的就是singleton和prototype

XML模式和注解模式的比较

  • 使用场景
    • XML:可以适用于任何场景,结构清晰,维护方便
    • 注解:如果这个类不是我们提供的,那么无法使用注解,开发方便
  • 整合开发
    • XML管理Bean,注解完成属性注入

Spring 的AOP的开发(XML)

  • Spring的AOP的简介

    • AOP思想最早是由AOP联盟组织提出的,Spring是使用这种框架最好的组织.Spring的AOP自己的实现方式非常繁琐,AspectJ是一个AOP的框架,后来Spring引入AspectJ作为自身AOP的开发.
    • Spring两套AOP开发的方式
      • Spring传统方式(弃用)
      • Spring基于ASpectJ的AOP的开发(使用)
  • Spring底层的AOP实现原理

    • 动态代理:
      • JDK的动态代理   只能对实现了接口的类产生代理(自动的)
      • Cglib的动态代理  对没有实现接口的类产生代理对象,产生子类对象
  • AOP开发中相关的术语

    • JoinPoint(连接点):可以被拦截到的点,增删改查的方法都可以被增强,这些方法就可以被称为是连接点
    • Pointcut(切入点):真正被拦截到的点,在实际开发中只对save方法进行了增强,所以save方法就称为是切入点
    • Advice(通知,增强):方法层面的增强.现在对save方法进行权限校验,权限校验的方法称之为通知
    • Introduction(引介):类层面的增强
    • Target(目标):被增强的对象,UserDao称之为是目标
    • weaving(织入):将通知应用到目标的过程,将权限校验的方法的代码应用到UserDao的save方法的过程,织入后产生结果代理类(Proxy)
    • Aspect(切面):多个通知和多个切入点组合!!!
  • AspectJ的XML的方式

    • 引入基本的开发包(6个)
    • 引入AOP开发的相关Jar包(4个)
    • 引入Spring的配置文件
      • 引入aop的约束
    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
    <aop:config>
    <!-- expression=表达式的配置来决定哪些类的那些方法需要进行增强(切入点) -->
    <aop:pointcut expression="execution(* spring.demo2.ProductDaoImpl.save(..))" id="pointcut1"/>
    <aop:pointcut expression="execution(* spring.demo2.ProductDaoImpl.delete(..))" id="pointcut2"/>
    <aop:pointcut expression="execution(* spring.demo2.ProductDaoImpl.update(..))" id="pointcut3"/>
    <aop:pointcut expression="execution(* spring.demo2.ProductDaoImpl.find(..))" id="pointcut4"/>

    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
    <!-- 前置通知 -->
    <!-- 在pointcut1这个切入点的前面应用checkPri方法 -->
    <aop:before method="checkPri" pointcut-ref="pointcut1"/>

    <!-- 后置通知 -->
    <!-- 在pointcut2这个切入点的后面应用writelog方法 -->
    <aop:after-returning method="writelog" pointcut-ref="pointcut2" returning="result"/>

    <!-- 环绕通知 -->
    <!-- 在pointcut3这个切入点环绕around方法 -->
    <aop:around method="around" pointcut-ref="pointcut3"/>

    <!-- 异常抛出通知 -->
    <!-- 在pointcut3这个切入点加入异常抛出通知afterThrowing方法 -->
    <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>

    <!-- 最终通知 -->
    <!-- 在pointcut3这个切入点加入异常抛出通知afterThrowing方法 -->
    <aop:after method="after" pointcut-ref="pointcut4"/>
    </aop:aspect>
    </aop:config>
  • Spring中的通知类型

    • 前置通知   在目标方法执行之前进行操作

      • 配置前置通知
        • 1
          2
          3
          4
          5
          <!-- 配置切面 -->
          <aop:aspect ref="myAspect">
          <!-- 在pointcut1这个切入点的前面应用checkPri方法 -->
          <aop:before method="checkPri" pointcut-ref="pointcut1"/>
          </aop:aspect>
* 可以获得切入点信息

  * 
1
2
public void checkPri(JoinPoint joinpoint){
System.out.println("权限校验..."+joinpoint);
  • 后置通知   在目标方法执行之后进行操作

    • 配置后置通知
      • 1
        2
        3
        <!-- 后置通知 -->
        <!-- 在pointcut2这个切入点的后面应用writelog方法 -->
        <aop:after-returning method="writelog" pointcut-ref="pointcut2" returning="result"/>
* 可以获得方法返回值

  * 
1
2
3
public void writelog(Object result){
System.out.println("日志记录..."+result);
}
  • 环绕通知   在目标方法执行前和后进行操作

    • 配置环绕通知

      • 1
        2
        3
        <!-- 环绕通知 -->
        <!-- 在pointcut3这个切入点环绕around方法 -->
        <aop:around method="around" pointcut-ref="pointcut3"/>
* 可以阻止目标方法的执行
  • 异常抛出通知 在程序出现异常的时候进行的操作

    • 配置异常抛出通知

      • 1
        2
        3
        <!-- 异常抛出通知 -->
        <!-- 在pointcut3这个切入点加入异常抛出通知afterThrowing方法 -->
        <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
* 
1
2
3
public void afterThrowing(Throwable ex){
System.out.println("异常抛出通知..."+ex.getMessage());
}
  • 最终通知   无论代码是否有异常总是会执行的操作

    • 配置最终通知

      • 1
        2
        3
        <!-- 最终通知 -->
        <!-- 在pointcut3这个切入点加入异常抛出通知afterThrowing方法 -->
        <aop:after method="after" pointcut-ref="pointcut4"/>
* 
1
2
3
4
5
/**
*最终通知:相当于finally代码块中的内容
*/
public void after(){
System.out.println("最终通知...");
  • Spring的切入点表达式写法

    • 基于execution的函数完成的
    • 语法
      • [访问修饰符] 方法返回值 包名.类名.方法名(参数)
      • public void spring.demo2.ProductDaoImpl.save(..)
        • *为通配符   +表示该类和子类   ..表示该包和子包

Spring 的AOP的开发(注解)

  • AspectJ的注解的方式

    • 引入基本的6个jar包
    • 引入aspectJ相关的4个jar包
    • 引入配置文件
    • 编写目标类并配置
    • 编写切面类并配置
  • 使用注解的AOP对目标类进行增强

    • 在配置文件中去打开注解的AOP开发

      <aop:aspectj-autoproxy/>

      1
      2
      3
      4
      5
      6
      7
      @Aspect
      public class MyAspectAnno {
      @Before(value="execution(* spring.demo1.OrderDao.save(..))" )
      public void before(){
      System.out.println("前置增强...");
      }
      }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {

@Resource(name="orderDao")
private OrderDao orderDao;
@Test
public void demo1(){
orderDao.save();
orderDao.update();
orderDao.find();
orderDao.delete();
}
}
  • Spring的注解的AOP的通知类型

    • @Before:    前置通知
    • @AfterReturning:后置通知
    • @Around:    环绕通知
    • @AfterThrowing: 异常抛出通知
    • @After:     最终通知
  • Spring的AOP的切入点的配置

    • 1
      2
      3
      //切入点注解:
      @Pointcut(value="execution(* spring.demo1.OrderDao.find(..))")
      private void pointcut1(){}

Spring的JDBC的模板的使用

  • Spring的JDBC的模板

    • Spring是EE开发的一站式的框架,有EE开发的每层的解决方案,Spring对持久层也提供了解决方案,ORM模块和JDBC的模板.
  • JDBC模板的使用

    • 引入基本的6的jar包
    • 引入数据库驱动jar包
    • 引入Spring的JDBC模板的jar包
    • 引入单元测试的jar包
  • 创建数据库和表springt.account

  • 使用JDBC的模板:保存数据

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      public class JdbcDemo1 {

      @Test
      public void demo1(){
      //创建连接池
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName("com.mysql.jdbc.Driver");
      dataSource.setUrl("jdbc:mysql:///springt");
      dataSource.setUsername("root");
      dataSource.setPassword("975864");
      //创建jdbc模板
      JdbcTemplate jdbcTemple = new JdbcTemplate(dataSource);
      jdbcTemple.update("insert into account values (null,?,?)", "xiaohu",10000d);
      }
      }
  • 将连接池和模板都交给Spring管理

    • 引入Spring的配置文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <!-- 配置Spring内置的连接池 -->	
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <!-- 属性注入 -->
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="url" value="jdbc:mysql:///spring5"/>
      <property name="username" value="root"/>
      <property name="password" value="975864"/>
      </bean>
      <!-- 配置SpringJDBC的模板 -->
      <bean id="jdbcTemplate" class="org.springframerwork.jdbc.core.JdbcTemplate">
      <property name="dataSource" ref="dataSource"></property>
      </bean>
    • 使用Spring 的数据库连接池和jdbc模板

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext.xml")
      public class JdbcDemo2 {
      @Resource(name="jdbcTemplate")
      private JdbcTemplate jdbcTemple;
      @Test
      public void demo1(){
      jdbcTemple.update("insert into account values (null,?,?)", "小天",100d);
      }
      }
  • 使用开源的数据库连接池

    • DBCP的使用

      • 引入两个jar包(dbcp和pool)

      • 配置DBCP连接池

        1
        2
        3
        4
        5
        6
        7
        <!-- 配置DBCP连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///springt"/>
        <property name="username" value="root"/>
        <property name="password" value="975864"/>
        </bean>
    • C3P0的使用

      • 引入c3p0的jar包

      • 配置C3P0连接池

        1
        2
        3
        4
        5
        6
        7
        8
        9

        <!-- 配置C3P0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///springt"/>
        <property name="user" value="root"/>
        <property name="password" value="975864"/>

        </bean>
    • 抽取配置到属性文件

      • 定义一个属性文件

        1
        2
        3
        4
        jdbc.driverClass=com.mysql.jdbc.Driver
        jdbc.url=jdbc:mysql:///springt
        jdbc.username=root
        jdbc.password=975864
      • 在Spring的配置文件中引入属性文件

        1
        2
        3
        4
        5
        6
        <!-- 第一种方式通过一个bean标签引入(很少用) -->
        <!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties"></property>
        </bean> -->
        <!-- 第二种方式通过context标签引入 -->
        <context:property-placeholder location="calsspath:jdbc.properties"/>
      • 引入属性文件的值

        1
        2
        3
        4
        5
        6
        <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>
  • 使用JDBC的模板完成CRUD的操作

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class JdbcDemo2 {
    @Resource(name="jdbcTemplate")
    private JdbcTemplate jdbcTemple;
    //增删改的操作相同
    @Test
    //保存操作
    public void demo1(){
    jdbcTemple.update("insert into account values (null,?,?)", "小水",1000d);
    }
    @Test
    //修改操作
    public void demo2(){
    jdbcTemple.update("update account set name=?,money=? where id=?","李四",2000d,5);
    }
    @Test
    //删除操作
    public void demo3(){
    jdbcTemple.update("delete from account where id=?",6);
    }
    @Test
    //查询操作:查询名称
    public void demo4(){
    String name = jdbcTemple.queryForObject("select name from account where id=?", String.class,5);
    System.out.println(name);
    }
    @Test
    //查询操作:查询记录总条数
    public void demo5(){
    Long count = jdbcTemple.queryForObject("select count(*) from account", Long.class);
    System.out.println(count);
    }
    @Test
    //查询操作:查询一条记录封装到一个对象中
    public void demo6(){
    Account account = jdbcTemple.queryForObject("select * from account where id=?", new MyRowMapper(), 5);
    System.out.println(account);
    }
    @Test
    //查询操作:查询多条记录封装到一个List集合中
    public void demo7(){
    List<Account> list = jdbcTemple.query("select * from account ", new MyRowMapper());
    for (Account account : list) {
    System.out.println(account);
    }
    }

    class MyRowMapper implements RowMapper<Account>{

    @Override
    public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
    Account account = new Account();
    //通过account属性的set方法里利用查询到的数据,封装成一个account对象并返回
    account.setId(rs.getInt("id"));
    account.setName(rs.getString("name"));
    account.setMoney(rs.getDouble("money"));
    return account;
    }

    }
    }

Spring的事务管理

  • 事物的回顾:

    • 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败
    • 事务的特性
      • 原子性:事务不可分割
      • 一致性:事务执行前后数据完整性保持一致
      • 隔离性:一个事务的执行不应该受到其他事务的干扰
      • 持久性:一旦事务结束,数据就持久化到数据库
    • 如果不考虑隔离性将会引发安全性问题
      • 读问题:
        • 脏读:一个事务读到另一个事务未提交的数据
        • 不可重复读:一个事务读到另一个事务已经提交的Update的数据,导致一个事务中多次查询的结果不一致
        • 虚读,幻读:一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询的结果不一致
      • 写问题:
        • 丢失更新
    • 解决读问题
      • 设置事务的隔离级别:
        1. Read uncommitted:未提交读,任何读问题都解决不了但是效率高
        2. Read committed:已提交读,解决脏读,但是不可重复读和虚读可能发生
        3. Repeatable:重复读,解决脏读和不可重复读,但是虚读可能发生
        4. Serializable:解决所有读问题,但是效率低,一般设置问2,3两个级别
  • Spring事务管理的API

    • Platform TransactionManager:平台事务管理器
      • 平台事务管理器:接口,是Spring用于管理事务的真正的对象
      • DataSourceTransactionManager:底层使用JDBC管理事务
      • HibernateTransactionManager:底层使用Hibernat管理事务
    • TransactionDefinition:事务定义信息
      • 事务定义:用于定义事务的相关的信息,隔离级别,超时信息,传播行为,是否只读
    • TransactionStatus:事务的状态
      • 事务状态:用于管理事务运行过程中,事务的状态的对象
  • 事务管理的 API 的关系

    • Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理 ,在事务管理过程中,产生各种状态,将这些状态信息记录到事务状态的对象
  • Spring的事务的传播行为

    • Spring中提供了七种传播行为

      • 保证多个操作在同一个事务中

        propagation: 增殖, 广传, 繁殖

        1. PROPAGATION_REQUIRED :默认值,如果A中有事务就会使用A中的事物,如果A中没有事务,创建一个新事物,将操作包含进来
        2. PROPAGATION_SUPPORTS:支持事务,如果A中有事务,使用A中的事务,如果A中没有事务,不使用事务
        3. PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务,如果A中没有事务,抛出异常
      • 保证多个操作不在同一个事务中

        1. PROPAGATION_REQUIRES_NEW:如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作,如果A中没有事务,创建一个新事务,包含自身的操作
        2. PROPAGATION_NOT_SUPPORTED:如果A中有事务,将A的事务挂起,不使用事务管理
        3. PROPAGATION_NEVER:如果A中有事务,报异常
      • 嵌套式事务

        1. PROPAGATION_NESTED:如果A中有事务,按照A的事务执行,执行完之后设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始的位置也可以选择回滚到保存点
    • 事务的传播行为主要用来解决业务层方法相互调用的问题

  • Spring事务管理

    • 搭建Spring事务管理的环境

      • 创建Service的接口和实现类

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        public class AccountServiceImpl implements AccountService{

        //注入DAO
        private AccountDao accountDao;
        public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
        }
        @Override
        /**
        * from:转出账号
        * to:转入账号
        * money:转账金额
        */
        public void transfer(String from, String to, Double money) {

        accountDao.outMoney(from,money);
        accountDao.inMoney(to, money);
        }

        }
* 创建DAO的接口和实现类

  
1
2
3
4
5
6
7
8
9
10
11
12
13
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

@Override
public void outMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money,from);
}

@Override
public void inMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money,to);
}

}
* 配置Service和DAO交给Spring管理
1
2
3
4
5
6
7
8
9
10
<!-- 配置Service======= -->
<bean id="accountService" class="tx.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>

</bean>

<!-- 配置Dao======= -->
<bean id="accountDao" class="tx.demo1.AccountDaoImpl">

</bean>
* 在DAO中写SQL语句控制 * 配置连接池
1
2
3
4
5
6
7
<!-- 配置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>
* 在DAO中注入Jdbc的模板
1
2
3
4
5
<!-- 配置Dao======= -->
<bean id="accountDao" class="tx.demo1.AccountDaoImpl">
<!-- <property name="jdbcTemplate" ref="jdbcTemple"></property> -->
<!-- 因为我们的类继承了JdbcDaoSupport所以我们需要JDBC模板的时候只要传给他一个连接池,他就会自动生成一个模板给我们 -->
<property name="dataSource" ref="dataSource"/>
  • 编程式事务管理(需要手动编写代码)

    • 配置平台事务管理器:

      1
      2
      3
      4
      <!-- 配置平台事务管理器====== -->
      <bean id="transactionManager" class="org.springframework.jdbc.darasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
      </bean>
    • 配置事务管理的模板类

      1
      2
      3
      4
      <!-- 配置事务管理的模板 -->
      <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactoinTemplate">
      <property name="transactionManager" ref="transactionManager"/>
      </bean>
    • 在业务层注入事务管理的模板

      1
      2
      3
      4
      5
      //注入事务管理的模板
      private TransactionTemplate transactionTemplate;
      public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
      this.transactionTemplate = transactionTemplate;
      }
      1
      2
      3
      4
      5
      6
      7
      <!-- 配置Service======= -->
      <bean id="accountService" class="tx.demo1.AccountServiceImpl">
      <property name="accountDao" ref="accountDao"/>
      <!-- 注入事务管理的模板 -->
      <property name="transactionTemplate" ref="transactionTemplate"/>

      </bean>
  • 声明式事务管理

    • XML方式的声明式事务管理

      • 引入AOP的四个开发包

      • 配置事务管理器

        1
        2
        3
        4
        <!-- 配置事务管理器=== -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DatasourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        </bean>
      • 配置事务的增强

        1
        2
        3
        4
        5
        6
        <!-- 配置事务的增强=== -->
        <tx:advice transaction-manager="transactionManager">
        <tx:attributes>
        <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
        </tx:advice>
      • AOP的配置

        1
        2
        3
        4
        5
        <!-- AOP的配置==== -->
        <aop:config>
        <aop:pointcut expression="execution(* tx.demo2.AccountServiceImpl.*(..))" id="pointcut1"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
        </aop:config>
  • 注解方式的声明式事务管理

    • 引入aop开发的jar包

    • 配置事务管理器

    • 开启注解事务

      1
      2
      <!-- 开启注解事务==== -->
      <tx:annotation-driven transaction-manager="transactionManager"/>
    • 添加注解

      1
      2
      @Transactional
      public class AccountServiceImpl implements AccountService{

Thanks!