注解 IOC & AOP

文章目录

Spring 的 IOC 的注解开发

IoC

Spring 的 IOC 注解开发入门

创建一个 web 项目,引入响应的 jar 包

在 spring4 的版本中,除了引入基本的开发包以外,还需要引入 aop 的包

引入 Spring 的配置文件
  • 在 src 下创建一个 applicationContext.xml
    • 引入约束:使用注解开发引入 context 约束
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->

</beans>
创建一个接口和实现类
开启Spring的组件扫描
 <!-- Spring的IOC的注解入门 -->
    <!-- 使用IOC的注解开发,配置组件扫描(告诉spring哪些包下的类要使用IOC的注解) -->
    <context:component-scan base-package="spring.demo1"/>
在类上添加注解
/**
 * @author Administrator
 * 
 */
@Component("userDao")//相当于<bean id="userDao" class="spring.demo1.UserDaoImpl">,作用就是将类UserDaoImpl交给spring,id是userDao
public class UserDaoImpl implements UserDao {

	@Override
	public void save() {
        System.out.println("Dao中保存方法执行了");		
	}

}
传统方式设置属性的值
@Test
    //传统方式
    public void demo1() {
    	UserDaoImpl userDaoImpl = new UserDaoImpl();
    	userDaoImpl.setName("小明");
    	userDaoImpl.save();
    }
注解方式设置属性的值
  • 注解方式:使用注解方式,可以没有 set 方法的
    • 属性如果有 set 方法,需要将属性注入的注解添加到 set 方法
    • 属性如果没有 set 方法,需要将属性注入的注解添加到属性上
@Component("userDao")//相当于<bean id="userDao" class="spring.demo1.UserDaoImpl">,作用就是将类UserDaoImpl交给spring,id是userDao
public class UserDaoImpl implements UserDao {
	
	@Value("王东")
	private String name;
	
//	public void setName(String name) {
//		this.name = name;
//	}

	@Override
	public void save() {
        System.out.println("Dao中保存方法执行了" + name);		
	}
}

Spring 的 IOC 的注解的详解

@Component:组件
  • 修饰一个类,将这个类将给 Spring 管理
  • 这个注解有三个衍生注解(功能类似),修饰类
    • @Controller:web 层
    • @Service:service 层
    • @Repository:dao 层
属性注入的注解
  • 普通属性:
    • @value:设置普通属性的值
  • 对象类型属性:
    • @Autowired:设置对象类型属性的值,但是按照类型完成属性的注入
    • 我们的习惯是按照名称完成属性的注入:必须让 @Autowired 和 @Qualifier 一起使用完成按照名称属性注入
    • @Resource:完成对象类型的属性的注入,按照名称完成属性的注入
Bean 的其他注解
  • 生命周期相关的注解(了解)
    • @PostConstruct:初始化方法
    • @PreDestroy:销毁方法
@Service("customerService")
public class CustomerService {
	
	@PostConstruct//相当于init-method
	public void init() {
    	System.out.println("Service被初始化了");
	}
	
    public void save() {
    	System.out.println("Service的save方法执行了");
    }
    
    @PreDestroy//相当于destroy-method
    public void destroy() {
    	System.out.println("Service被销毁了");
    }
}
  • Bean 的作用范围的注解
    • @Scope:作用范围
      • singleton:默认单例
      • prototype:多例
      • request
      • session
      • globalsession

IOC 的 xml 和 注解开发的比较

xml 和 注解的比较
  • 使用场景
    • xml:可以使用于任何场景
      • 结构清晰,维护方便
    • 注解:有些地方用不了,这个类不是自己提供的(因为要在源代码中修改)
      • 开发方便
xml 和注解整合开发
  • 使用 xml 管理 Bean,注解完成属性注入

Spring 的 AOP 的 XML 开发(重点)

AOP 概述

什么是 AOP ?
  • AOP :面向切面编程
  • OOP :面向对象编程
    AOP 是 OOP 的扩展和延伸,解决 OOP 开发遇到的问题。
Spring 底层的 AOP 实现原理
  • 动态代理
    • JDK 动态代理:只能对实现接口的类产生代理对象
    • Cjlib 动态代理(类似于 Javassist 第三方代理技术),对没有实现接口的类产生代理对象,生成子类对象
Spring 的 AOP 底层实现(了解)
JDK 动态代理
/**
 * @author Administrator
 * 使用JDK动态代理对UserDao产生代理
 */

public class JDKProxy implements InvocationHandler{
	//将被增强的对象传递到代理中
	private UserDao userDao;
	public JDKProxy(UserDao userDao) {
		this.userDao = userDao;
	}
	/**
	 * @author Administrator
	 * 产生UserDao代理的方法
	 */
    public UserDao createProxy() {
    	UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
    	
    	return userDaoProxy;
    }
    
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//判断方法名是不是save
		if("save".equals(method.getName())) {
			//增强
			System.out.println("权限校验");
		}
		return method.invoke(userDao, args);
	}
}
Cglib 动态代理
  • Cglib:第三方开源代码生成类库,可以动态添加类的属性和方法
/**
 * @author Administrator
 * Cglib动态代理
 */
public class CglibProxy implements MethodInterceptor{
 
	private CustomerDao customerDao;
	
	public CglibProxy(CustomerDao customerDao) {
		this.customerDao = customerDao;
	}
	
	public CustomerDao createProxy() {
		//创建cglib核心类的对象
		Enhancer enhancer = new Enhancer();
		//设置父类
		enhancer.setSuperclass(customerDao.getClass());
		//设置回调
		enhancer.setCallback(this);
		//创建代理对象
		CustomerDao proxy = (CustomerDao) enhancer.create();
		
		return proxy;
	}

	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		if("save".equals(method.getName())) {
			//增强
			System.out.println("权限校验");
			return methodProxy.invokeSuper(proxy, args);
		}
		return methodProxy.invokeSuper(proxy,args);
	}  
}

Spring 的 AOP 的开发(AspectJ 的 XML 的方式)

Spring 的 AOP 的简介
  • AOP 思想最早由 AOP 联盟提出的,Spring 使用这种思想最好的框架。
    • Spring 的 AOP 有自己实现的方式(非常繁琐)。AspectJ 是一个 AOP 的框架,Spring 引入 AspectJ 作为自身的 AOP 的开发。
    • Spring 有两套 AOP 方式
      • Spring 传统方式(弃用)
      • Spring 基于 AspectJ 的 AOP 的开发(使用)
AOP 开发中相关术语
  • Joinpoint:连接点,可以被拦截到的点
  • Pointcut:切入点,真正被拦截到的点
  • Advice:通知、增强
  • Introduction:引介

在这里插入图片描述

Spring 的 AOP 的入门(AspectJ 的 xml 的方式)

创建 web 项目,引入 jar 包
  • 引入基本的开发包
  • 引入 aop 开发的相关 jar 包
引入 Spring 的配置文件
编写目标类并完成配置
<!-- 配置目标对象:被增强的对象 -->
     <bean id="productDao" class="spring.demo3.ProductDaoImpl"></bean>
编写测试类
  • Spring 整合 Junit 单元测试
/**
 * @author Administrator
 * AOP 入门
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
	
	@Resource(name="productDao")
	private ProductDao productDao;
	
    @Test
    public void demo1() {
    	productDao.save();
    	productDao.update();
    	productDao.delete();
    	productDao.find();
    }
}
编写一个切面类
/**
 * @author Administrator
 * 切面类
 */
public class MyAspectXML {
    public void checkPri() {
    	System.out.println("权限校验============");
    }
}
配置切面类
   <!-- 将切面类交给spring管理 -->
     <bean id="myAspect" class="spring.demo3.MyAspectXML"></bean>
通过 AOP 的配置实现对目标生成代理
 <!-- 通过AOP的配置完成对目标类产生代理 -->
     <aop:config>
         <!-- 表达式配置哪些类的哪些方法需要进行增强 -->
         <aop:pointcut expression="execution()" id="pointcut1"/>
         <!--配置切面  -->
         <aop:aspect ref="myAspext">
             <aop:before method="checkPri" pointcut-ref="pointcut1"/>
         </aop:aspect>
     </aop:config>

Spring 中通知类型

前置通知:在目标方法执行之前进行操作
  • 前置通知:获得切入点的信息
<!--配置切面  -->
         <aop:aspect ref="myAspect">
             <aop:before method="checkPri" pointcut-ref="pointcut1"/>
         </aop:aspect>
后置通知:在目标方法执行之后进行操作
  • 后置通知:获得方法的返回值
 <!--配置切面  -->
         <aop:aspect ref="myAspect">
             <!-- 前置通知 -->
             <aop:before method="checkPri" pointcut-ref="pointcut1"/>
             <!-- 后置通知 -->
              <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
          </aop:aspect>
     </aop:config>
环绕通知:在目标方法执行之前和之后操作
  • 环绕通知可以阻止目标方法的执行
<!--配置切面  -->
         <aop:aspect ref="myAspect">
             <!-- 前置通知 -->
             <aop:before method="checkPri" pointcut-ref="pointcut1"/>
             <!-- 后置通知 -->
             <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
              <!-- 环绕通知 -->
             <aop:around method="around" pointcut-ref="pointcut3"/>
          </aop:aspect>
     </aop:config>
异常抛出通知:在程序出现异常的时候进行的操作
 <!--配置切面  参数throwing的作用是打印异常信息-->
         <aop:aspect ref="myAspect">
             <!-- 异常抛出通知 -->
             <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
          </aop:aspect>
最终通知:无论代码是否有异常,总是执行
 <!-- 最终通知 -->
             <aop:after method="after" pointcut-ref="pointcut4"/>
引介通知(不用会)

Spring 的切入点表达式写法

切入点表达式语法
  • 基于 execution 的函数完成的
  • 语法:
    • [访问修饰符] 方法的返回值 包名.类名.方法名(参数)
    • 比如:public void spring.demo3.CustomerDao.save(…)
    • 表达式中任何一个地方都可以用 * 来表示
      • spring.demo3.CustomerDao+.save(…):+ 表示当前类和其子类都可以被增强

Spring 的 AOP 的基于 AspectJ 注解开发

创建项目,引入 jar 包

引入配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx.xsd">

编写目标类

<!-- 配置目标类 -->
    <bean id="orderDao" class="spring.demo1.OrderDao">
        
    </bean>

编写切面类并配置

/**
 * @author Administrator
 * 切面类,注解的切面类
 */
public class MyAspectAnno {
	
	public void before() {
		System.out.println("前置增强===========");
	}

}

   <!-- 配置切面类 -->
    <bean id="myAspect" class="spring.demo1.MyAspectAnno"></bean>

使用注解的 AOP 对目标类进行增强

  • 在配置文件中打开注解的 AOP 开发
  <!-- 在配置文件中开启注解的AOP开发 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  • 在切面类上使用注解
/**
 * @author Administrator
 * 切面类,注解的切面类
 */
@Aspect
public class MyAspectAnno {
	
	@Before(value="execution(* spring.demo1.OrderDao.save(..))")
	public void before() {
		System.out.println("前置增强===========");
	}
}

编写测试类

/**
 * @author Administrator
 * Spring的AOP的注解开发
 */
@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.delete();
	    orderDao.find();
  } 
}

Spring 的注解的 AOP 的通知类型

  • @Before:前置通知
  • @AfterReturning:后置通知
//后置通知
	@AfterReturning(value="execution(* spring.demo1.OrderDao.delete(..))",returning="result")
	public void afterReturning(Object result) {
		System.out.println("后置增强==========" + result);
	}
  • @Around:环绕通知
//环绕通知
	@Around(value="spring.demo1.OrderDao.update(..)")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("环绕前增强=========");
		Object object = joinPoint.proceed();
		System.out.println("环绕后增强=========");
		return object;
	}
  • @AfterThrowing:异常抛出通知
//异常抛出通知
	@AfterThrowing(value="execution(* spring.demo1.OrderDao.find(..))",throwing="e")
    public void afterThrowing(Throwable e) {
		System.out.println("异常抛出通知========" + e.getMessage());
	}
  • @After:最终通知
//最终通知
	@After(value="execution(* spring.demo1.OrderDao.find(..))")
	public void after() {
		System.out.println("最终增强===========");
	}

Spring 的 AOP 的切入点的配置

//异常抛出通知
	@AfterThrowing(value="execution(* spring.demo1.OrderDao.find(..))",throwing="e")
    public void afterThrowing(Throwable e) {
		System.out.println("异常抛出通知========" + e.getMessage());
	}
	
	//最终通知
	@After(value="MyAspectAnno.pointcut1()")
	public void after() {
		System.out.println("最终增强===========");
	}
	
	//切入点注解
	@Pointcut(value="execution(* spring.demo1.OrderDao.find(..))")
	private void pointcut1() {}

Spring 的 JDBC 的模板的使用

Spring 是 EE 开发的一站式框架,有 EE 开发的每层的解决方案。Spring 对持久层也提供了解决方案,ORM 模块和 JDBC 模板。
Spring 提供了很多的模板用于简化开发。

JDBC 模板入门

  • 创建一个项目,引入 jar 包

    • 引入基本开发包
    • 数据库驱动
    • Spring 的 JDBC 模板 jar 包
  • 创建一个数据库和表

  • 使用 JDBC 模板来保存数据

/**
 * @author Administrator
 * JDBC模板的使用
 */
public class JDBCDemo1 {
    @Test
    public void demo1() {
    	//创建连接池
    	DriverManagerDataSource dataSource = new DriverManagerDataSource();
    	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    	dataSource.setUrl("jdbc:mysql:///spring4_day03");
    	dataSource.setUsername("root");
    	dataSource.setPassword("1183787376");
    	//创建jdbc模板
    	JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    	jdbcTemplate.update("insert into account values(null,?,?)", "张三",10000d);
    }
}

将连接池和模板交给Spring管理

引入Spring的配置文件
<!-- 配置Spring的内置的连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSourc">
        <!-- 属性注入 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///spring4_day03"/>
        <property name="username" value="root"/>
        <property name="password" value="1183787376"/>
    </bean>
    
    <!-- 配置Spring的JDBC模板 -->
    <bean id="jdbcTemplate" class="org.springframeword.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

使用 JDBC 模板

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JDBCDemo2 {
	
	@Resource(name="jdbcTemplate")
	private JdbcTemplate jdbcTemplate;
	
	@Test
	public void demo2() {
		jdbcTemplate.update("insert into account values(null,?,?)","王五",20000d);
	}

}

使用开源的数据库连接池

DBCP 的使用
  • 引入 jar 包
<!-- 配置DBCP连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///spring4_day03"/>
        <property name="username" value="root"/>
        <property name="password" value="1183787376"/>
    </bean>
C3P0 的使用
  • 引入 C3P0 连接池的 jar 包
<!-- 配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring4_day03"/>
        <property name="user" value="root"/>
        <property name="password" value="1183787376"/>
    </bean>

抽出配置到属性文件

定义一个属性文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_day03
jdbc.username=root
jdbc.password=1183787376
在 Spring 配置文件中引入属性文件
  • 第一种方式
<!-- 第一种方式通过bean标签引入(很少) -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties"></property>
    </bean>
  • 第二种方式
<!-- 第二种方式:通过context标签引入 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
使用 JDBC 模板完成 CRUD 操作
增删改操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JDBCDemo2 {
	
	@Resource(name="jdbcTemplate")
	private JdbcTemplate jdbcTemplate;
	
	//保存操作
	@Test
	public void demo1() {
		jdbcTemplate.update("insert into account values(null,?,?)","老陈",50000d);
	}

	//修改操作
	@Test
	public void demo2() {
		jdbcTemplate.update("update account set name = ?, money = ? where id = ?", "张四","23456",1);
	}
	
	//删除操作
	@Test
	public void demo3() {
		jdbcTemplate.update("delete from account where id = ?", 2);
	}
}

查询操作
//查询操作
	public void demo4() {
		String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 5);
		System.out.println(name);
	}
	
	@Test
    public void demo5() {
    	Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
    	System.out.println(count);
    }

Spring 的事务管理

什么是事务

  • 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败

事务的特性

  • 原子性:事务不可分割
  • 一致性:事务执行前后数据完整性保持一致
  • 隔离性:一个事务的执行不应该受到其他事务的干扰
  • 持久性:一旦事务结束,数据就持久保持到数据库

如果不考虑隔离性就会引发安全性问题

  • 读问题
    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交的update数据,导致一个事务中多次查询到的结果不一致
    • 虚度、幻读:一个事务读到另一个事务insert的数据,导致一个事务多次查询的结果不一致
  • 写问题
    • 丢失更新

解决读问题

  • 设置隔离级别
    • Read uncommitted:未提交读,任何读问题解决不了
    • Read committed:已提交读,解决脏读,但是不可重复读和虚读可能发生
    • Repeatable read:重复读,解决脏读和不可重复读,但是虚读可能发生
    • Serializable:解决所有问题

Spring 的事务管理 API

PlatformTransactionManager:平台事务管理器

  • 平台事务管理器:接口,是Spring用于管理事务的真正的对象。
    • DataSourceTransactionManager:底层使用 JDBC 管理事务
    • HibernateTransactionManager:底层使用 Hibernate 管理事务

TransactionDefinition:事务的定义信息

  • 事务定义:用于定义事务的相关信息,如隔离级别、超时信息、传播行为和是否只读

TransactionStatus:事务的状态

  • 事务的状态:用于记录在事务的管理过程中,事务的状态对象

事务管理的 API 的关系

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

Spring 事务的传播行为

什么是事物传播行为?
  • Spring 中提供了七种事务传播行为:
    • 保证多个操作在同一事务中
      • PROPAGATION_REQUIRED(重点) :默认值,如果A(外层方法)中有事务,使用A中的事务,如果A中没有事务,创建一个新的事务,将操作包含进来。
      • PROPAGATION_SUPPROTS:支持事务,如果A中有事务,使用A中的事务,如果A中没有事务,不使用事务。
      • PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务。如果A中没有事务,抛出异常。
    • 保证多个操作不在同一个事务中
      • PROPAGATION_REQUIRES_NEW(重点):如果A(外层方法)中有事务,将A的事务挂起,创建新的事务,只包含自身的操作。如果A中没有事务,创建一个新事务包含自身操作。
      • PROPAGATION_NOT_SUPPOET如果A中有事务,将A的事务挂起,不适用事务管理。
      • PROPAGATION_NEVER:如果A中有事务,报异常。
    • 嵌套事务
      PROPAGATION_NESTED(重点):嵌套事务,如果A中有事务,按照A的事务执行,执行完成后设置一个保存点,执行B中的操作。如果没有异常,执行通过;如果有异常,可以选择回滚到最初始的位置,也可以回滚到保存点。

Spring的事务管理

搭建Spring的事务管理环境
  • 创建Service的接口和实现类
  • 创建Dao的接口和实现类
  • 配置Service和Dao:交给Spring管理
<!-- 配置Service -->
    <bean id="accountService" class="te.demo1.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    
    <!-- 配置Dao -->
    <bean id="accountDao" class="te.demo1.AccountDaoImpl"></bean>
  • 在Dao中编写扣钱和加钱的方法:

  • 配置了连接池和JDBC模板

<!-- 配置C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_day03"/>
        <property name="user" value="root"/>
        <property name="password" value="1183787376"/>
    </bean>
    
     <!-- 配置Spring的JDBC模板 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
  • 在Dao中注入JDBC模板
<!-- 配置Dao -->
    <bean id="accountDao" class="te.demo1.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
  • 测试

Spring 的事务管理:第一类:编程式事务(需要手动编写代码)

第一步:配置平台事务管理器
<!-- 配置平台事务管理器 -->
    <bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref = "dataSource"/>
    </bean> 
第二步:Spring提供了事务管理的模板类
  • 配置事务管理的模板类
<!-- 配置事务管理的模板 -->
    <bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref = "transactionManager"></property>
    </bean>
第三步:在业务层注入事务管理的模板
 <!-- 配置Service -->
    <bean id="accountService" class="te.demo1.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <!-- 注入事务管理的模板 -->
        <property name="transactionTemplate" ref = "transactionTemplate"/>
    </bean>
第四步:编写事务管理的代码
public void transfer(final String from, final String to, final Double money) {
		
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				 accountDao.outMoney(from, money);
				 int i = 1 / 0;
			     accountDao.inMoney(to, money);
			}
		});
	}

Spring的事务管理:第二类:声明式事务管理(通过配置实现)— AOP

XML 方式的声明式事务管理
  • 第一步:引入 aop 的开发包
  • 第二步:恢复转账环境
  • 第三步:配置事务管理器
<!-- 配置事务管理器 -->
    <bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref = "dataSource"/>
    </bean>
  • 第四步:配置事务的增强
<!-- 配置事务的增强 -->
    <tx:advice transaction-manager = "transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation = "REQUIRED"/>
        </tx:attributes>
    </tx:advice>
  • 第五步:AOP 的配置
  <!-- 配置事务的增强 -->
    <tx:advice id = "txAdvice" transaction-manager = "transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation = "REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- aop的配置 -->
    <aop:config>
        <aop:pointcut expression="execution(* tx.demo2.AccountServiceImpl.*(..))" id="pointcut1"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref = "pointcut1"/>
    </aop:config>
注解方式的声明式事务管理
  • 引入aop开发包
  • 恢复转账环境
  • 配置事务管理器
  • 开启注解事务
 <!-- 开启注解事务 -->
    <tx:annotation-driven transaction-manager = "transactionManager"/>
  • 使用注解
@Transactional
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);
		int i = 1 / 0;
		accountDao.inMoney(to, money);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值