spring事物(1)-----手写spring的事物框架

一,区别声明式事物和编程式事物

所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事物其实就是编程式事物+spring的AOP代理,在里面我们是见不到手动的begin commit  和rollback的。

管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。

声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

下面我们通过案例来看看。

二,案例

2.1,spring事物自带的几种通知

package com.qingruihappy.service;

//user 服务层
public interface UserService {
    public void add();
}
package com.qingruihappy.service.impl;

import org.springframework.stereotype.Service;

import com.qingruihappy.service.UserService;
/**
 * 注意事物出异常的话一定不要吃掉(try cath ,而是要throw往外抛,否则事物是不起作用的。原因我们后面讲)
 * @author qingruihappy
 * @data   2018年11月19日 上午12:21:21
 * @说明:
 */
//user 服务层
@Service
public class UserServiceImpl implements UserService {
    // spring 事务封装呢? aop技术
    public void add() {
      System.out.println("往数据库添加数据.........");
    }

}
package com.qingruihappy.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

// 切面类
@Component//注入到spring的容器中来
@Aspect//表示是一个切面
public class AopLog {

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

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

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

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

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

        // 调用方法之前执行
        System.out.println("环绕通知 调用方法之前执行");
        proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出溢出不会执行后面代码
        // 调用方法之后执行
        System.out.println("环绕通知 调用方法之后执行");
    }

}
package com.qingruihappy.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy.service.UserService;

public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
        userService.add();
    }

}

结果:

前置通知 在方法之前执行...
环绕通知 调用方法之前执行
往数据库添加数据.........
前置通知 在方法之后执行...
运行通知
环绕通知 调用方法之后执行

2.2,一个不加事务的案例

<?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"></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>

这个spring的配置对下面的两个案例都其作用。

package com.qingruihappy1.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@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);
    }

}
package com.qingruihappy1.service;

//user 服务层
public interface UserService {
    public void add();
}
package com.qingruihappy1.service.impl;

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

import com.qingruihappy1.service.UserService;
import com.qingruihappy2.dao.UserDaob;

//user 服务层
@Service
public class UserServiceImpla implements UserService {
    @Autowired
    private UserDaob userDao;
    public void add() {
        // 注意在这里没有事物的话,执行完userDao.add("test001", 20);就会把数据插入到数据库中去的。
            userDao.add("test001", 20);
            int a=1/0;
            //因为这里没有事物所以当报错的时候tes001会插入到数据库中,而test002不会插入到数据库中。
            System.out.println("################");
            userDao.add("test002", 21);
    }

}
package com.qingruihappy1.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy1.service.UserService;

public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImpla");
        userService.add();
    }

}

结果:

Exception in thread "main" updateResult:1
java.lang.ArithmeticException: / by zero
    at com.qingruihappy1.service.impl.UserServiceImpla.add(UserServiceImpla.java:17)
    at com.qingruihappy1.test.Test001.main(Test001.java:13)

数据库:

这是因为在没有事物的情况下,执行完service的userDao.add("test001", 20);这一行代码的时候,数据库里面立马就有数值了,也不存在所谓的回滚了。

2.3,手写编程式事物

package com.qingruihappy2.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaob {
    @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);
    }

}
package com.qingruihappy2.service;

//user 服务层
public interface UserService {
    public void add();
}
package com.qingruihappy2.service.impl;

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

import com.qingruihappy2.dao.UserDaob;
import com.qingruihappy2.service.UserService;
import com.qingruihappy2.transaction.TransactionUtils;

//user 服务层
@Service
public class UserServiceImplb implements UserService {
    @Autowired
    private UserDaob userDao;
    @Autowired
    private TransactionUtils transactionUtils;

    // spring 事务封装呢? aop技术
    public void add() {
        TransactionStatus transactionStatus = null;
        try {
            // 开启事务
            transactionStatus = transactionUtils.begin();
            userDao.add("test001", 20);
            System.out.println("开始报错啦[email protected]!!");
             int i = 1 / 0;
            System.out.println("################");
            userDao.add("test002", 21);
            // 提交事务
            //有错的话就会回滚的,这个时候当执行完userDao.add("test001", 20);,并不会插入到数据库中,只有确保commit的时候才会提交到数据库中去的
            //出错的话就会rollback的。
            if (transactionStatus != null)
                transactionUtils.commit(transactionStatus);
        } catch (Exception e) {
            e.getMessage();
            // 回滚事务
            if (transactionStatus != null)
                transactionUtils.rollback(transactionStatus);
        }
    }

}
package com.qingruihappy2.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

//编程事务(需要手动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);
    }

}
package com.qingruihappy2.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy2.service.UserService;

public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImplb");
        userService.add();
    }

}

2.4,手写声明式事务

package com.qingruihappy3.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoc {
    @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);
    }

}
package com.qingruihappy3.service;

//user 服务层
public interface UserService {
    public void add();
}
package com.qingruihappy3.service.impl;

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

import com.qingruihappy1.dao.UserDao;
import com.qingruihappy3.service.UserService;
import com.qingruihappy3.transaction.TransactionUtilsc;

//user 服务层
@Service
public class UserServiceImplc implements UserService {
    @Autowired
    private UserDao userDao;

    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();
        }
        //在spring的事物中我们一般不要trycatch 因为一旦吃掉异常的话就不会走到反射类的AopTransaction的afterThrowing()异常方法中去了
        //这个时候假如我们的业务场景必须的try的话,我们在catch的里面加上手动回滚的代码TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        //记住必须每个catch都加的。
/*        userDao.add("test001", 20);
        int i = 1 / 0;
        System.out.println("################");
        userDao.add("test002", 21);*/
    }

}
package com.qingruihappy3.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

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

    // 获取事务源
    @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);
    }

}
package com.qingruihappy3.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.qingruihappy3.transaction.TransactionUtilsc;

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

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

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

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

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy3.service.UserService;

public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImplc");
        userService.add();
    }

}

事务是程序运行如果没有错误,会自动提交事物,如果程序运行发生异常,则会自动回滚。

如果使用了try捕获异常时.一定要在catch里面手动回滚。

事务手动回滚代码

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

原文地址:https://www.cnblogs.com/qingruihappy/p/9986524.html

时间: 2024-09-29 20:31:14

spring事物(1)-----手写spring的事物框架的相关文章

手写 Spring 事务、IOC、DI 和 MVC

Spring AOP 原理 什么是 AOP? AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率 应用场景:日志记录,性能统计,安全控制,事务处理,异常处理 AOP 底层实现原理是采用代理实现的 Spring 事务 基本特性: 原子性 隔离性 一致性 持久性 事务控制分类: 编程式事务:手动控制事务操作 声明式事务:通过 AOP 控制事务 编程式事务实现 使用编程事务实现手动事务 @Component @Scope("prototype") public

我是这样手写Spring的,麻雀虽小,五脏俱全

人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多年的研究经验,用不到400行代码来描述Spring IOC.DI.MVC的精华设计思想,并保证基本功能完整.首先,我们先来介绍一下Spring的三个阶段,配置阶段.初始化阶段和运行阶段(如图):配置阶段:主要是完成application.xml配置和Annotation配置.初始化阶段:主要是加载

一个老程序员是如何手写Spring MVC的

人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多年的研究经验,用不到400行代码来描述SpringIOC.DI.MVC的精华设计思想,并保证基本功能完整. 首先,我们先来介绍一下Spring的三个阶段,配置阶段.初始化阶段和运行阶段(如图): 配置阶段:主要是完成application.xml配置和Annotation配置. 初始化阶段:主要是

记录一次阿里架构师全程手写Spring MVC 原

人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多年的研究经验,用不到400行代码来描述SpringIOC.DI.MVC的精华设计思想,并保证基本功能完整. 首先,我们先来介绍一下Spring的三个阶段,配置阶段.初始化阶段和运行阶段(如图): 配置阶段:主要是完成application.xml配置和Annotation配置. 初始化阶段:主要是

Spring系列之手写一个SpringMVC

目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 Spring系列之AOP的原理及手动实现 Spring系列之手写注解与配置文件的解析 引言 在前面的几个章节中我们已经简单的完成了一个简易版的spring,已经包括容器,依赖注入,AOP和配置文件解析等功能.这一节我们来实现一个自己的springMvc. 关于MVC/SpringMVC springMvc是一个基于mvc模式的web框架,SpringMVC框架是一种提供了MVC(模型 - 视图 - 控制器)架

手写 Spring

手写 Spring 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背下来 1)配置阶段 配置 web.xml: XDispatchServlet 设定 init-param: contextConfigLocation = classpath:application.xml 设定 url-pattern: /* 配置 Annotation: @XController @XService @XAutowired @XRequestMapping 2)初始化阶

手写Spring框架,加深对Spring工作机制的理解!

在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越来越轻松,我们用 Spring Boot 分分钟可以新建一个Web项目. 记得自己刚开始工作的时候还是在用Servlet写Web项目,自己写数据库连接池,用原生JDBC操作数据库,好了不发散了.回到这篇文章的主题,今天通过手写Spring框架,帮大家深入了解一下Spring的工作机制,文中涉及的代码

携程系统架构师带你手写spring mvc,解读spring核心源码!

讲师简介: James老师 系统架构师.项目经理 十余年Java经验,曾就职于携程.人人网等一线互联网公司,专注于java领域,精通软件架构设计,对于高并发.高性能服务有深刻的见解, 在服务化基础架构和微服务技术有大量的建设和设计经验. 课程内容: 1.为什么读Spring源码? 如果你是一名JAVA开发人员,你一定用过Spring Framework. 作为一款非常经典的开源框架,从2004年发布的1.0版本到现在的5.0版本,经历了14年的洗礼, 持久不衰 与其说现在是JAVA的天下, 不如

从零开始手写 spring ioc 框架,深入学习 spring 源码

IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过. 但是 spring 源码存在一个问题,那就是过于抽象,导致学习起来成本上升. 所以本项目由渐入深,只实现 spring 的核心功能,便于自己和他人学习 spring 的核心原理. spring 的核心 Spring 的核心就是 spring-beans,后面的一切 spring-boot,spr