Spring AOP与事务

Spring AOP

AOP概念

Aop概念:面向切面编程,可以将业务逻辑进行隔离开。
基于动态代理对原有的方法进行增强。
(1)有接口 使用jdk的动态代理 创建接口实现类的代理对象。使用Proxy类的newProxyInstance()方法创建代理对象。

  • 方法参数:
    (1)类加载器
    (2)增强方法所在实现类的接口,可以是多个
    (3)实现接口InvocationHandler()

(2)没有接口 使用cglib动态代理创建类子类的代理对象。
Enhancer.create(class type,callback)

  • 方法参数
    (1)class类
    (2)callback 实现接口 MethodInterceptor() 重写intercept方法

详情见:https://blog.csdn.net/lgb1997/article/details/109076744

AOP常用术语

(1)连接点:可增强的方法
(2)切入点:实际增强的方法
(3)切    面:就是将通知应用到切入点的过程
(4)通    知:增强逻辑
(5)织    入:将增强添加到目标的具体连接点上的过程 。


切面
@Before 前置通知
@After 表示在方法执行之后
@AfterReturning 方法返回值之后
@Around 环绕执行 在方法之前之后都执行
@AfterThrowing 异常通知,如果被增强的方法中出现异常才会执行

Spring 事务

事务概念

  • 事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,要么都失败。
  • spring中事务的四个特性(ACID)
    (1)原子性:操作不可分割,要么都成功,要么都失败。
    (2)一致性:操作之前 和操作之后的总体是一致的。
    (3)隔离性:多人操作互不影响。
    (4)持久性:操作后数据会在数据库中更改。

事务隔离级别

  • 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
  • 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读
  • 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

如果没有隔离性,在并发操作中会出现 脏读、不可重复读、幻读。

  • 脏读:A事务读取到B事务尚未提交的数据,即当B事务发生错误回滚时,A事务读取的回滚之前的数据就是脏数据。
  • 不可重复读:A事务两次读取同一份数据,在第二次读的时候,这时事务B修改了这份数据导致两次读取的数据不一致。
  • 幻读:一个未提交的事务读取到另一个事务添加的数据。

事务传播行为

propagation特征
Require如果当前没有事务,就新建一个事务。如果已经存在一个事务,就加入到这个事务中。
Require-new新建事务,如果当前存在事务,把当前事务挂起。
Supports支持当前事务,如果当前没有事务,就以非事务方式执行。
Not Supported以非事务方式执行操作。如果当前存在事务,把当前事务挂起。
Mandatory使用当前的事务,如果当前没有事务,则抛出异常。
Never以非事务方式执行操作。如果当前没有事务,抛出异常。
Nested如果当前存在事务,则在嵌套事务中执行。如果当前没有事务,则执行与Required相似的操作。

Demo

此处测试创建的是java项目,操作数据库使用的是jdbcTemplate。需要导的包
在这里插入图片描述

配置类

package com.pec.aop.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration //声明配置类
@ComponentScan(basePackages = {"com.pec.aop"}) //开启扫描
@EnableAspectJAutoProxy //开启生成代理对象
@EnableTransactionManagement//开启事务
public class SpringConfig {
	//配置数据库连接
	@Bean
	public DruidDataSource getDataSource() {
		
		DruidDataSource dataSource=new DruidDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/jpa?serverTimezone=GMT%2B8&characterEncoding=utf-8");
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("Luoguibin6!");
		return dataSource;
	}
	//创建jdbc模板对象
	@Bean
	public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource) {
		JdbcTemplate jdbcTemplate=new JdbcTemplate();
		jdbcTemplate.setDataSource(dataSource);
		return jdbcTemplate;
	}
	//配置事务管理器对象
	@Bean
	public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource) {
		DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
		dataSourceTransactionManager.setDataSource(dataSource);
		return dataSourceTransactionManager;
	}
}

实体类

package com.pec.aop.empty;

import java.io.Serializable;

public class Mobile implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer id;
	private Integer no;
	private String mobileName;
	private double price;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Integer getNo() {
		return no;
	}
	public void setNo(Integer no) {
		this.no = no;
	}
	public String getMobileName() {
		return mobileName;
	}
	public void setMobileName(String mobileName) {
		this.mobileName = mobileName;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
}

mapper

package com.pec.aop.mapper;

import com.pec.aop.empty.Mobile;

public interface AopMapper {
	Integer update(Mobile mobile);
	Integer updatePrice(Double price);
}

mapper实现类

package com.pec.aop.mapperImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.pec.aop.empty.Mobile;
import com.pec.aop.mapper.AopMapper;

@Repository
public class AopMapperImpl implements AopMapper {
	@Autowired
	JdbcTemplate jdbcTemplate;
	
	@Override
	public Integer update(Mobile mobile) {
		String sql ="update mobile set price=?,mobile_name=?";
		Object[] args= {mobile.getPrice(),mobile.getMobileName()};
		int i=jdbcTemplate.update(sql,args);
		return i;
	}

	@Override
	public Integer updatePrice(Double price) {
		String sql1="update mobile set price=?";
		int a=10/0;
		
		int j=jdbcTemplate.update(sql1, price);
		return j;
	}
}

service

package com.pec.aop.service;

import com.pec.aop.empty.Mobile;

public interface AopService {
	 Integer update(Mobile mobile,Double price);

}

service实现

package com.pec.aop.serviceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pec.aop.empty.Mobile;
import com.pec.aop.mapper.AopMapper;
import com.pec.aop.service.AopService;
@Service
public class AopServiceImpl implements AopService{
	@Autowired
	AopMapper aopMapper;

	@Override
	@Transactional
	public Integer update(Mobile mobile,Double price) {
		Integer i=aopMapper.update(mobile);
		aopMapper.updatePrice(price);
		return i;
	}

}

测试类

package test;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.pec.aop.config.SpringConfig;
import com.pec.aop.empty.Mobile;
import com.pec.aop.service.AopService;
public class AopTest {
	
	@SuppressWarnings("resource")
	@Test
	public void add() {
		ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
		AopService aopService=context.getBean("aopServiceImpl",AopService.class);
		Mobile mobile=new Mobile();
		mobile.setMobileName("xiaomi");
		mobile.setPrice(3000);
		double price=2000;
		aopService.update(mobile,price);
	}
}

测试结果

在这里插入图片描述
执行完后控制台:
在这里插入图片描述
执行后表数据:
在这里插入图片描述
可以看到由于在实现类上加了@Transactional注解,mobile_name也没有变化。

@Transactional注解参数

参数名称

功能描述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")

指定多个异常类名称:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值