文章目录
- Spring 的 IOC 的注解开发
- Spring 的 AOP 的 XML 开发(重点)
- Spring 的 AOP 的基于 AspectJ 注解开发
- Spring 的 JDBC 的模板的使用
- Spring 的事务管理
- Spring 的事务管理 API
Spring 的 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
- @Scope:作用范围
IOC 的 xml 和 注解开发的比较
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);
}
}