1.AOP
1.概述
AOP (Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。(是对面向对象编程的补充延续,)
面向切面编程思想:是将程序中非业务代码(提交事务,打印日志,权限验证,统一异常处理)提取分离出来,然后再调用业务代码时,通过代理对象,帮助调用这些提取出来的非业务代码,这样在业务代码不用显示的调用非业务代码,做到业务代码和非业务代码的分离,降低了耦合度。
面向切面编程的好处: 模块之间耦合度降低
面向切面编程原理:动态代理模式,给业务代码生成代理对象
AOP思想是java中的,不是spring中专有的,是spring使用AOP这一编程思想
2.AOP基本概念
连接点(Joinpoint):类中可以被增强的方法,这个方法就被称为连接点
切入点(pointcut):
类中有很多方法可以被增强,但实际中只有 add 和 update 被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)
public void insert() { System.out.println("新增"); /* this.commit();//虽然把一些非业务代码进行抽取,但是依然还要调用 this.printLog();*/ // System.out.println(10/0); }
通知(Advice):
通知是指一个切面在特定的连接点要做的事情(增强的功能)。通 知分为方法执行前通知,方法执行后通知,环绕通知等.
目标(Target):
代理的目标对象(连接点,切入点所在类)
代理(Proxy):
向目标对象应用通知时创建的代理对象
2.SpringAOP实现
1.在pom.xml引入AOP相关依赖jar包
<!--AOP 相关 jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
2.配置注解支持,启动自动代理
<!--开启自动代理 启动AspectJ支持-->
<aop:aspectj-autoproxy />
3.AspectJ 常用通知
1.@Before
前置通知 在方法执行前调用执行
2.@After
后置通知 在业务方法执行完后调用执行 即使代码出现异常也会执行
3.@AfterReturnning
返回通知 方法成功执行之后调用执行,方法出现异常不执行
4.@AfterThrowing
异常通知 当业务代码出现异常后通知
5.@Around
环绕通知 可以在业务方法执行之前,之后,处异常时添加功能
下面是自定义的环绕通知及测试代码
@Around(value ="execution(* com.ffyc.springpro.dao.AdminDao.*(..))")
public void around(ProceedingJoinPoint joinPoint){
System.out.println("前置通知");
try {
Object[] objects = joinPoint.getArgs();
System.out.println(Arrays.toString(objects));//获取到目标方法参数
Object object= joinPoint.proceed();//调用目标业务方法
System.out.println("返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知");
}
System.out.println("后置通知");
}
public class Test3 {
public static void main(String[] args) {
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
AdminService adminService=applicationContext.getBean("adminService",AdminService.class);
adminService.insertAdmin();
adminService.updateAdmin();
adminService.deleteAdmin();
}
}
运行结果:
4.Spring事物管理
1.相关概念
事务管理本质上是数据库提供的一种管理机制。
数据库事务管理:是对一次数据库操作过程中执行的多条语句进行管理,确保一次对操作过程中的多条 sql 要么都执行成功,要么都不执行,从而保证数据一致性
spring事务管理:是spring框架对事务提交这一功能进行封装,程序员在业务开发中不需要显示的提交事务。( sqlSession.commit() )
Spring中的事务管理分为两种形式:
1.编程式事务管理
需要程序员在代码中控制事务提交和回滚。
2.声明式事务管理
声明事务底层使用了AOP思想,可以为方法添加事务功能,它的控制是方法级别的。
基于注解实现的 spring 事务管理
Spring 框架,提供事物管理实现类是 DataSourceTransactionManager.
配置事物管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
注解方式
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在类或方法上使用@Transactional 标签即可.
@Transactional 可以添加到方法上,也可添加到类上面,如果添加到类上面,此类中的所有方法都在spring事务管理中进行
@Transactiona放到service层进行事务管理,这样的话就可以对提交的事务进行事务管理。
声明式事务不生效的场景
数据库起始数据
1.@Transactional 应用在非 public 修饰的方法上
AdminDao:
public void insert1() {
jdbcTemplate.update("insert into admin(account,password,gender)values(?,?,?)", "zhangsan","1111","男");
}
@Transactional
public void insert2() {
jdbcTemplate.update("insert into admin(account,password,gender)values(?,?,?) ","lisi","1234","男");
}
AdminService:
@Transactional
void insertAdmin() throws UnsupportedEncodingException {
adminDao.insert1();
adminDao.insert2();
}
Test3:
public class Test3 {
public static void main(String[] args) throws UnsupportedEncodingException {
/* AdminService adminService=new AdminService();
ApplicationContext applicationContext= new
ClassPathXmlApplicationContext("spring.xml");
AdminService adminService=applicationContext.getBean("adminService",AdminService.class);
adminService.insertAdmin();
adminService.updateAdmin();
adminService.deleteAdmin();
}
}
2.异常被 catch 捕获导致失效
@Transactional
public void insertAdmin(){
adminDao.insert1();
try {
System.out.println(10/0);
adminDao.insert2();
} catch (Exception e){
e.printStackTrace();
}
// adminDao.insert1();
// adminDao.insert("zhangsan");
}
3.出现编译期异常
AdminDao:
@Transactional
public void insert1() {
jdbcTemplate.update("insert into admin(account,password,gender)values(?,?,?)", "zhangsan","1111","男");
}
@Transactional
public void insert2() {
jdbcTemplate.update("insert into admin(account,password,gender)values(?,?,?) ","lisi","1234","男");
}
AdminService:
@Transactional
public void insertAdmin() throws UnsupportedEncodingException {
adminDao.insert1();
"aa".getBytes("utf-999");
adminDao.insert2();
/* try {
System.out.println(10/0);
adminDao.insert2();
} catch (Exception e){
e.printStackTrace();
}*/
/* adminDao.insert1();
adminDao.insert2();*/
}
Test3:
public class Test3 {
public static void main(String[] args) throws UnsupportedEncodingException {
/* AdminService adminService=new AdminService();
adminService.saveAdmin();*/
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
AdminService adminService=applicationContext.getBean("adminService",AdminService.class);
adminService.insertAdmin();
adminService.updateAdmin();
adminService.deleteAdmin();
}
}
解决办法:可以将@Transactional配置到AdminService类上,并添加rollbackFor =Exception.class 这样的话所有的异常都会回滚
@Service(value = "adminService")
@Transactional(rollbackFor =Exception.class)
//在方法中出现了编译期异常,还是会提交事务 可以将rollbackFor =Exception.class 这样的话所有的异常都会回滚
public class AdminService {
public void insertAdmin() throws UnsupportedEncodingException {
adminDao.insert1();
"aa".getBytes("utf-999");
adminDao.insert2();
/* try {
System.out.println(10/0);
adminDao.insert2();
} catch (Exception e){
e.printStackTrace();
}*/
/* adminDao.insert1();
adminDao.insert2();*/
}
public void updateAdmin(){
adminDao.update();
}
public void deleteAdmin(){
adminDao.delete();
}
public AdminService() {
System.out.println("adminService无参构造");
}
public void setAdminDao(AdminDao adminDao) {
this.adminDao = adminDao;
}
}
4.数据库引擎不支持事务,mysql中只有innodb引擎支持事务