目录

  • 一、Spring事务
  • 二、AOP简介
  • 三、静态代理
  • 四、动态代理设计模式
  • 五、AOP注解事务实现
  • 1、POM
  • 2、spring.xml
  • 3、注解方式实现AOP
  • 六、Spring事务特性
  • 1、原子性(Atomicity)
  • 2、一致性(Consistency)
  • 3、隔离性(Isolation)
  • 4、持久性(Durability)
  • 七、手写Spring编程事务
  • 1、spring.xml
  • 2、TransactionUtils
  • 3、手写编程事务
  • 八、AOP整合编程事务
  • 1、AopTransaction
  • 2、UserServiceImpl


一、Spring事务

  • Spring事务是基于AOP环绕通知和异常通知实现的
  • Spring事务:编程式事务、声明式事务
  • Spring事务底层:使用编程式事务+AOP技术进行包装的=声明式事务

二、AOP简介

  • AOP概念:Aspect Oriented Programming面向切面编程,解决代码复用问题
  • AOP底层实现原理:代理设计模式
  • 为什么要使用AOP技术:代码复用、解耦
  • AOP的主要应用:日志记录,性能统计,安全控制,事务处理,异常处理

三、静态代理

//user 服务层
public interface UserService {
	public void add();
}
//user 服务层
public class UserServiceImpl implements UserService {
	public void add() {
		System.out.println("往数据库添加数据...");
	}
}
// 静态代理设计模式
public class UserServiceProxy {
	private UserService userService;
	public UserServiceProxy(UserService userService) {
		this.userService = userService;
	}
	public void add() {
		System.out.println("静态代理 开启事务");
		userService.add();
		System.out.println("静态代理  提交事务");
	}
}
public class App{
	public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		// userService.add();
		UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
		userServiceProxy.add();
	}
}

spring分布式日志 spring分布式事务框架_后端

四、动态代理设计模式

//user 服务层
public interface UserService {
	public void add();
}
//user 服务层
public class UserServiceImpl implements UserService {
	public void add() {
		System.out.println("往数据库添加数据...");
	}
}
// 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象
public class InvocationHandlerImpl implements InvocationHandler {
    private Object target;// 这其实业务实现类对象,用来调用具体的业务方法
    // 通过构造函数传入目标对象

    public InvocationHandlerImpl(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("使用jdk动态代理 开启事务");
        result = method.invoke(target, args);
        System.out.println("使用jdk动态代理 提交事务");
        return result;
    }

    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        // 被代理对象
        UserService userService = new UserServiceImpl();
        InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userService);
        ClassLoader loader = userService.getClass().getClassLoader();
        Class<?>[] interfaces = userService.getClass().getInterfaces();
        // 主要装载器、一组接口及调用处理动态代理实例
        UserService newProxyInstance = (UserService) Proxy.newProxyInstance(loader, interfaces,
                invocationHandlerImpl);
        newProxyInstance.add();
    }
}

spring分布式日志 spring分布式事务框架_spring_02

五、AOP注解事务实现

1、POM

<dependencies>
		<!-- 引入Spring-AOP等相关Jar -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.6.1</version>
		</dependency>
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.5.3</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.1_2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.37</version>
		</dependency>
	</dependencies>

2、spring.xml

  • 路径位置:src/main/resources/spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">
    <context:component-scan base-package="com.sjyl"></context:component-scan>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 -->
</beans>

3、注解方式实现AOP

public interface UserService {
    public void add();
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("往数据库添加数据...");
    }
}

@Component// 切面类
@Aspect
public class AopLog {

    // aop 编程里面有几个通知: 前置通知 后置通知 运行通知 异常通知 环绕通知
    @Before("execution(* com.sjyl.aop.UserService.add(..))")
    public void before() {
        System.out.println("前置通知 在方法之前执行...");
    }

    // 后置通知 在方法运行后执行
    @After("execution(* com.sjyl.aop.UserService.add(..))")
    public void after() {
        System.out.println("前置通知 在方法之后执行...");
    }

    // 运行通知
    @AfterReturning("execution(* com.sjyl.aop.UserService.add(..))")
    public void returning() {
        System.out.println("运行通知");
    }

    // 异常通知
    @AfterThrowing("execution(* com.sjyl.aop.UserService.add(..))")
    public void afterThrowing() {
        System.out.println("异常通知");
    }

    // 环绕通知 在方法之前和之后处理事情
    @Around("execution(* com.sjyl.aop.UserService.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        // 调用方法之前执行
        System.out.println("环绕通知 调用方法之前执行");
        proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出异常不会执行后面代码
        // 调用方法之后执行
        System.out.println("环绕通知 调用方法之后执行");
    }
}
public class Test001 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
        userService.add();
    }
}

spring分布式日志 spring分布式事务框架_spring_03

六、Spring事务特性

1、原子性(Atomicity)

  • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响

2、一致性(Consistency)

  • 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  • 拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性

3、隔离性(Isolation)

  • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行

4、持久性(Durability)

  • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
  • 例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误

七、手写Spring编程事务

1、spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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">
	<context:component-scan base-package="com.sjyl"></context:component-scan>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 -->

	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>

	<!-- 2. JdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 3.配置事务 -->
	<bean id="dataSourceTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

</beans>

2、TransactionUtils

//编程事务(需要手动begin 手动回滚  手都提交)
@Component
public class TransactionUtils {

	// 获取事务源
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	// 开启事务
	public TransactionStatus begin() {
		TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
		return transaction;
	}

	// 提交事务
	public void commit(TransactionStatus transaction) {
		dataSourceTransactionManager.commit(transaction);
	}

	// 回滚事务
	public void rollback(TransactionStatus transaction) {
		dataSourceTransactionManager.rollback(transaction);
	}
}

3、手写编程事务

public interface UserService {

	public void add();
}

@Repository
public class UserDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	public void add(String name, Integer age) {
		String sql = "INSERT INTO t_users(NAME, age) VALUES(?,?);";
		int updateResult = jdbcTemplate.update(sql, name, age);
		System.out.println("updateResult:" + updateResult);
	}
}

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private TransactionUtils transactionUtils;

    // spring 事务封装呢? aop技术
    public void add() {
        TransactionStatus transactionStatus = null;
        try {
            // 开启事务
            transactionStatus = transactionUtils.begin();
            userDao.add("test001", 20);
            System.out.println("开始报错啦!@!!");
            // int i = 1 / 0;
            System.out.println("################");
            userDao.add("test002", 21);
            // 提交事务
            if (transactionStatus != null)
                transactionUtils.commit(transactionStatus);
        } catch (Exception e) {
            e.getMessage();
            // 回滚事务
            if (transactionStatus != null)
                transactionUtils.rollback(transactionStatus);
        }
    }
}

八、AOP整合编程事务

1、AopTransaction

//切面类  基于手手动事务封装
@Component
@Aspect
public class AopTransaction {
	@Autowired
	private TransactionUtils transactionUtils;

	// TransactionUtils 不要实现为单例子: 如果为单例子的话可能会发生线程安全问题
	// // 异常通知
	@AfterThrowing("execution(* com.sjyl.service.UserService.add(..))")
	public void afterThrowing() {
		System.out.println("回滚事务");
		// 获取当前事务 直接回滚
		TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
	}

	// 环绕通知 在方法之前和之后处理事情
	@Around("execution(* com.sjyl.service.UserService.add(..))")
	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

		// 调用方法之前执行
		System.out.println("开启事务");
		TransactionStatus transactionStatus = transactionUtils.begin();
		proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出溢出不会执行后面代码
		// 调用方法之后执行
		System.out.println("提交事务");
		transactionUtils.commit(transactionStatus);
	}
}

2、UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
	@Autowired
	private UserDao userDao;
	@Autowired
	private TransactionUtils transactionUtils;

	public void add() {
		// 注意事项: 在使用spring事务的时候,service 不要try 最将异常抛出给外层aop 异常通知接受回滚
		try {
			userDao.add("test001", 20);
			int i = 1 / 0;
			System.out.println("################");
			userDao.add("test002", 21);
		} catch (Exception e) {
			e.printStackTrace();
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
	}
}