Spring框架之AOP详解

news2024/12/24 10:09:23

目录

一、前言

1.1.Spring简介

1.2.使用Spring的优点

二、Spring之AOP详解

2.1.什么是AOP

2.2.AOP在Spring的作用

2.3.AOP案例讲解

三、AOP案例实操

3.0.代理小故事(方便理解代理模式)

3.1.代码演示

3.2.前置通知

3.3.后置通知

3.3.环绕通知

3.4.异常通知

3.4.过滤通知

四、总结


一、前言

1.1.Spring简介

Spring翻译过来就是春天的意思,它的出现也是给广大程序员带来了春天🍃。

Spring框架最初由Rod Johnson创建,他于2002年写了一本名为《Expert One-on-One J2EE Design and Development》的书,书中详细介绍了一些与J2EE技术有关的设计模式和最佳实

践。该书的成功激发了Rod Johnson继续探索J2EE开发的方法,最终他开发了Spring框架。

2004年,Spring框架发布了第一个正式版本1.0,这个版本包括IoC容器、AOP、数据访问等核心特性。

1.2.使用Spring的优点

Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。
Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
   

然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
   目的:解决企业应用开发的复杂性
   功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
   范围:任何Java应用
   简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

二、Spring之AOP详解

2.1.什么是AOP

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.2.AOP在Spring的作用

提供声明式事务;允许用户自定义切面

以下名词需要了解下:

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。
  • 适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)

SpringAOP中,通过Advice定义横切逻辑,Spring中支持6种类型的Advice:

即 Aop 在 不改变原有代码的情况下 , 去增加新的功能  

通知类型连接点实现接口
前置通知方法前
org.springframework.aop.MethodBeforeAdvice
后置通知方法后
org.springframework.aop.AfterReturningAdvice
环绕通知方法前后
org.aopalliance.intercept.MethodInterceptor
异常抛出通知方法抛出异常
org.springframework.aop.ThrowsAdvice
引介通知类中添加新的方法属性
org.springframework.aop.support.IntroductionInterceptor
过滤通知除去一些不必要的通知
org.springframework.aop.support.RegexpMethodPointcutAdvisor

2.3.AOP案例讲解

假如我们写了一个网上书城的项目,内有书籍管理模块,用户管理等等。。。

场景一:甲方工作人员在操作过程中,上架了一本严令禁止的小说,上架没几分钟觉得不妥又下架了,但是他的这一举动被领导所看到了,领导质问甲方工作人员,可是甲方工作人员已经下架了没有确凿的证据,甲方工作人员死活不承认。

场景二:对于平台而已,客户已经下单并付款商品,但是由于工作人员起了私心,从中牟利并删除了下单及付款信息。

结论:以上的两种常见,所做之事都没有人去监管,也没有确凿的证据,所以一般而言系统都会添加日志功能,也就是在每一个业务板块添加日志记录(记录谁在什么时候调用了什么方法传递了什么参数以及执行结果等等...)这种代码我称之为非业务核心代码。

非业务核心代码:简单来说就是不影响我的业务代码,但又是我不得不要的代码所以称之为核心。

三、AOP案例实操

3.0.代理小故事(方便理解代理模式)

曾经有一座宝岛,岛上生活着一群友善而勤劳的小精灵。这些小精灵从事各种工作,其中最重要的工作是守护岛上最神秘的宝藏。这宝藏拥有无穷的智慧和力量,但只有被真正的勇者找到才能释放出来。

然而,宝藏周围的环境异常危险,危险程度逐渐加大,小精灵们感到困惑和无助。他们意识到,他们需要一位有经验的勇者来保护宝藏,但是岛上却找不到这样的人。

为了解决这个问题,小精灵们决定使用代理模式来寻找一位勇者。他们决定制作一面魔法镜子,并在岛的入口处放置它。这面魔法镜子可以连接到大陆的勇者公会。

镜子中时常有勇者进入,但也有许多冒牌勇者试图骗取宝藏。因此,小精灵们派自己最聪明的代表做了一个重要的决定。代表将进来的勇者进行一系列的测试,以确定他们是否真正有能力保护宝藏。

这位代表小精灵名叫智慧咪咪。她利用专业的问答、智力和武器测试来辨别真正的勇者,并将测试结果反馈给大陆的勇者公会。

随着时间的推移,越来越多的勇者听说了这座神秘宝岛上的宝藏,并前来挑战。智慧咪咪的测试也越来越完善准确。

最终,一位真正的勇者通过了所有的测试,被智慧咪咪确认为真正的勇者。他们获得了宝藏的力量,并保护宝藏不受伤害。岛上的小精灵们感到非常安心,因为他们终于找到了能够保护宝藏的勇者。

通过使用代理模式,小精灵们成功地解决了守护宝藏的难题。岛上的宝藏仍然拥有着无穷的智慧和力量,而勇者也继续保护宝藏不受任何威胁。

这个故事告诉我们,代理模式不仅可以帮助我们解决问题,还可以保护我们珍贵的财富和资源。无论是在虚拟世界还是现实世界,代理模式都能发挥着重要的作用,帮助我们实现各种目标和保护我们的利益。

3.1.代码演示

以下代码模拟我们平常编写代码流程(书籍管理)

IBookBiz.java(书籍管理接口定义)

package com.csdn.xw.aop.biz;

public interface IBookBiz {
	// 购书
	public boolean buy(String userName, String bookName, Double price);

	// 发表书评
	public void comment(String userName, String comments);
}

BookBizImpl.java(实现类)

package com.csdn.xw.aop.biz.impl;

import com.csdn.xw.aop.biz.IBookBiz;
import com.csdn.xw.aop.exception.PriceException;

public class BookBizImpl implements IBookBiz {

	public BookBizImpl() {
		super();
	}

	public boolean buy(String userName, String bookName, Double price) {
		// 通过控制台的输出方式模拟购书
		if (null == price || price <= 0) {
			throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
	}

	public void comment(String userName, String comments) {
		// 通过控制台的输出方式模拟发表书评
		System.out.println(userName + " say:" + comments);
	}

}

PriceException.java(书籍价格异常类)

package com.csdn.xw.aop.exception;

public class PriceException extends RuntimeException {

	public PriceException() {
		super();
	}

	public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public PriceException(String message, Throwable cause) {
		super(message, cause);
	}

	public PriceException(String message) {
		super(message);
	}

	public PriceException(Throwable cause) {
		super(cause);
	}
	
}

Spring-Context.xml

 <!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>

Demo01.java(模拟)

package com.csdn.xw.aop.demo;

import com.csdn.xw.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Java方文山
 * @compay csdn_Java方文山
 * @create 2023-08-17-16:14
 */
public class demo01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/Spring-Context.xml");
        IBookBiz bookbiz = (IBookBiz) context.getBean("bookBiz");
        bookbiz.buy("Java方文山","《大话西游》",9.9d);
        bookbiz.comment("Java方文山","绝了");
    }
}

测试结果:

下面我们用AOP的方式分别演示前置通知、后置通知、环绕通知、异常通知、过滤通知。

3.2.前置通知

MyMethodBeforeAdvice.java

package com.csdn.xw.aop.advice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 买书、评论前加系统日志
 * @author Administrator
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//		在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去
		String target = arg2.getClass().getName();
		String methodName = arg0.getName();
		String args = Arrays.toString(arg1);
		System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");
	}

}

Spring-Context.xml

<!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<!--前置通知-->
    <bean class="com.csdn.xw.aop.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean>


    <!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
        <!--配置目标对象-->
        <property name="target" ref="bookBiz"></property>

        <!--配置代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.csdn.xw.aop.biz.IBookBiz</value>
            </list>
        </property>

        <!--配置通知-->
        <property name="interceptorNames">
           <list>
               <value>methodBeforeAdvice</value>
           </list>
        </property>

    </bean>

Demo01.java(模拟)

package com.csdn.xw.aop.demo;

import com.csdn.xw.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Java方文山
 * @compay csdn_Java方文山
 * @create 2023-08-17-16:14
 */
public class demo01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/Spring-Context.xml");
        IBookBiz bookbiz = (IBookBiz) context.getBean("proxyFactoryBean");
        bookbiz.buy("Java方文山","《大话西游》",9.9d);
        bookbiz.comment("Java方文山","绝了");
    }
}

测试结果:

3.3.后置通知

MyAfterReturningAdvice.java

package com.csdn.xw.aop.advice;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 买书返利
 * @author Administrator
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
		String target = arg3.getClass().getName();
		String methodName = arg1.getName();
		String args = Arrays.toString(arg2);
		System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0);
	

	}

}

Spring-Context.xml

 <!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean> 
<!--后置通知-->
    <bean class="com.csdn.xw.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>

    <!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
        <!--配置目标对象-->
        <property name="target" ref="bookBiz"></property>

        <!--配置代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.csdn.xw.aop.biz.IBookBiz</value>
            </list>
        </property>

        <!--配置通知-->
        <property name="interceptorNames">
           <list>
               <value>myAfterReturningAdvice</value>
           </list>
        </property>

Demo01.java无变化我们直接看打印结果:

3.3.环绕通知

MyMethodInterceptor.java

package com.csdn.xw.aop.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.util.Arrays;

/**
 * 环绕通知
 * 	包含了前置和后置通知
 * 
 * @author Administrator
 *
 */
public class MyMethodInterceptor implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		String target = arg0.getThis().getClass().getName();
		String methodName = arg0.getMethod().getName();
		String args = Arrays.toString(arg0.getArguments());
		System.out.println("【环绕通知调用前:】:"+target+"."+methodName+"("+args+")被调用了");
//		arg0.proceed()就是目标对象的方法
		Object proceed = arg0.proceed();
		System.out.println("【环绕通知调用后:】:该方法被调用后的返回值为:"+proceed);
		return proceed;
	}

}

Spring-Context.xml

 <!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<!--环绕通知-->
    <bean class="com.csdn.xw.aop.advice.MyMethodInterceptor" id="methodInterceptor"></bean>

    <!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
        <!--配置目标对象-->
        <property name="target" ref="bookBiz"></property>

        <!--配置代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.csdn.xw.aop.biz.IBookBiz</value>
            </list>
        </property>

        <!--配置通知-->
        <property name="interceptorNames">
           <list>
               <value>methodInterceptor</value>
           </list>
        </property>

    </bean>

Demo01.java无变化我们直接看打印结果:

3.4.异常通知

MyThrowsAdvice.java

package com.csdn.xw.aop.advice;

import com.csdn.xw.aop.exception.PriceException;
import org.springframework.aop.ThrowsAdvice;



/**
 * 出现异常执行系统提示,然后进行处理。价格异常为例
 * @author Administrator
 *
 */
public class MyThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing(PriceException ex) {
		System.out.println("【异常通知】:当价格发生异常,那么执行此处代码块!!!");
	}
}

Spring-Context.xml

 <!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
<!--异常通知-->
    <bean class="com.csdn.xw.aop.advice.MyThrowsAdvice" id="advice"></bean>

    <!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
        <!--配置目标对象-->
        <property name="target" ref="bookBiz"></property>

        <!--配置代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.csdn.xw.aop.biz.IBookBiz</value>
            </list>
        </property>

        <!--配置通知-->
        <property name="interceptorNames">
           <list>
               <value>advice</value>
           </list>
        </property>

    </bean>

Demo01.java(模拟)我们将价格改为负数

package com.csdn.xw.aop.demo;

import com.csdn.xw.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Java方文山
 * @compay csdn_Java方文山
 * @create 2023-08-17-16:14
 */
public class demo01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/Spring-Context.xml");
        IBookBiz bookbiz = (IBookBiz) context.getBean("proxyFactoryBean");
        bookbiz.buy("Java方文山","《大话西游》",-9.9d);
        bookbiz.comment("Java方文山","绝了");
    }
}

测试结果:

3.4.过滤通知

Spring-Context.xml

<!--目标对象-->
    <bean class="com.csdn.xw.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>
    <!--后置通知-->
    <bean class="com.csdn.xw.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
    <!--过滤配置-->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
        <property name="advice" ref="myAfterReturningAdvice"></property>
        <property name="pattern" value=".*buy"></property>
    </bean>

    <!--代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
        <!--配置目标对象-->
        <property name="target" ref="bookBiz"></property>

        <!--配置代理接口-->
        <property name="proxyInterfaces">
            <list>
                <value>com.csdn.xw.aop.biz.IBookBiz</value>
            </list>
        </property>

        <!--配置通知-->
        <property name="interceptorNames">
           <list>
               <value>regexpMethodPointcutAdvisor</value>
           </list>
        </property>

    </bean>

测试结果:

 

四、总结

Q:谈谈你对aop的理解?

A:aop是面向切面编程,程序是由上至下执行,但是aop面向切面编程不是,aop的程序执行,首先当程序执行到目标对象的目标方法时,如果连接点上有前置通知,则先执行前置通知,再执行目标方法,如果没有前置通知,则继续执行目标方法,再查看目标方法上有无后置通知,如果有,则再进行执行后置通知。

不管是前置通知、后置通知、环绕通知、异常通知、过滤通知,代码都是非业务核心代码,如日志、事物的管理。

到这里我的分享就结束了,欢迎到评论区探讨交流!!

如果觉得有用的话还请点个赞吧 ♥  ♥

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/892172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聚观早报|俞敏洪东方甄选带货北京特产;京东物流上半年盈利

【聚观365】8月17日消息 俞敏洪东方甄选直播间带货北京特产 京东物流上半年实现盈利 百度CTO称大语言模型为人工智能带来曙光 腾讯控股第二季度盈利262亿元 2023中国家庭智慧大屏消费白皮书 俞敏洪东方甄选直播间带货北京特产 近日&#xff0c;东方甄选在北京平谷区开播&…

Linux:shell脚本:基础使用(5)《正则表达式-sed工具》

sed是一种流编辑器&#xff0c;它是文本处理中非常中的工具&#xff0c;能够完美的配合正则表达式使用&#xff0c;功能不同凡响。 处理时&#xff0c;把当前处理的行存储在临时缓冲区中&#xff0c;称为“模式空间”&#xff08;pattern space&#xff09;&#xff0c;接着用s…

数据库MySQL 创建表INSERT

创建表 常见数据类型(列类型) 列类型之整型 unsigned的用法 列类型之bit 二进制表示 bit&#xff08;8&#xff09;表示一个字节 列类型之小数 1.单精度float 双精度double 2.decimal 自定义 M为小数点前面有多少位 D是小数点后面有多少位 列类型之字符串 1.char( 字符 )…

实现简单的element-table的拖拽效果

第一步&#xff0c;先随便创建element表格 <el-table ref"dragTable" :data"tableData" style"width: 100%" border fit highlight-current-row><el-table-column label"日期" width"180"><template slot-sc…

element-Plus中el-menu菜单无法正常收缩解决方案

<el-menu :collapse"true">如图所示收缩之后&#xff0c;有子级的菜单还有箭头文字显示 从代码对比看层级就不太对了&#xff0c;嵌套错误了&#xff0c;正常下方官网的ul标签下直接是li&#xff0c;在自己的代码中&#xff0c;ul标签下是div标签&#xff0c;层…

爬虫工具的选择与使用:阐述Python爬虫优劣势

作为专业爬虫ip方案解决服务商&#xff0c;我们每天都面对着大量的数据采集任务需求。在众多的爬虫工具中&#xff0c;Python爬虫凭借其灵活性和功能强大而备受青睐。本文将为大家分享Python爬虫在市场上的优势与劣势&#xff0c;帮助你在爬虫业务中脱颖而出。 一、优势篇 灵活…

初试rabbitmq

rabbitmq的七种模式 Hello word 客户端引入依赖 <!--rabbitmq 依赖客户端--><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.8.0</version></dependency> 生产者 imp…

相对于多进程,你真的知道为什么要使用多线程吗(C/C++多线程编程)

目录 前言 线程VS进程 POSIX线程库的使用 线程创建 线程等待 线程分离 线程状态 可结合态线程实例 分离态线程实例 线程退出 线程的同步与互斥 同步互斥的概念 互斥锁&#xff08;互斥&#xff09; 互斥锁的使用步骤 总结说明 信号量 信号量的使用步骤 条件变…

数据包如何游走于 Iptables 规则之间?

在前文《Linux路由三大件》中&#xff0c;我们提到了 iptables 可以修改数据包的特征从而影响其路由。这个功能无论是传统场景下的 防火墙&#xff0c;还是云原生场景下的 服务路由&#xff08;k8s service&#xff09;、网络策略(calico network policy) 等都有依赖。 虽然业…

7.逻辑结构VS物理结构

第四章 文件管理 7.逻辑结构VS物理结构 ​   fopen这个函数做的事情就是打开了“test.txt”这个文件&#xff0c;并且“w”说明是以“写”的方式打开的&#xff0c;以“写”的方式打开才能往这个文件里写入数据&#xff0c;如果文件打开了那么fp这个指针就可以指向和这个文件…

Eclipse如何设置快捷键

在eclopse设置注释行和取消注释行 // 打开eclipse&#xff0c;依次打开&#xff1a;Window -> Preferences -> General -> Key&#xff0c;

数据结构--关键路径

数据结构–关键路径 AOE⽹ 在 带权有向图 \color{red}带权有向图 带权有向图中&#xff0c;以 顶点表示事件 \color{red}顶点表示事件 顶点表示事件&#xff0c;以 有向边表示活动 \color{red}有向边表示活动 有向边表示活动&#xff0c;以 边上的权值表示完成该活动的开销 \…

HCIE--------------------------------------第一节OSPF快速收敛(OSPF与BGP联动)

一、OSPF快速收敛概述 OSPF快速收敛是为了提高路由的收敛速度而做的扩展特性&#xff0c;包括&#xff1a;PRC&#xff08;Partial Route Calculation&#xff0c;部分路由计算&#xff09;和智能定时器。 同时&#xff0c;OSPF支持故障恢复快速收敛&#xff0c;例如通过OSPF …

Linux Server 20.04 Qt5.14.2配置Jetson Orin Nano Developer Kit 交叉编译环境

最近公司给了我一块Jetson Orin Nano的板子&#xff0c;让我搭建交叉编译环境&#xff0c;所以有了下面的文章 一 :Qt5.14.2交叉编译环境安装 1.准备 1.1设备环境 1.1.1 Server: Ubuntu20.04: Qt 源码 5.14.2 Qt 软件 5.14.2 gcc 版本 9.4.0 g 版本 9.4.0 1.1.2 Jetson …

在 React 中获取数据的6种方法

一、前言 数据获取是任何 react 应用程序的核心方面。对于 React 开发人员来说&#xff0c;了解不同的数据获取方法以及哪些用例最适合他们很重要。 但首先&#xff0c;让我们了解 JavaScript Promises。 简而言之&#xff0c;promise 是一个 JavaScript 对象&#xff0c;它将…

openGauss学习笔记-42 openGauss 高级数据管理-触发器

文章目录 openGauss学习笔记-42 openGauss 高级数据管理-触发器42.1 语法格式42.2 参数说明42.3 示例 openGauss学习笔记-42 openGauss 高级数据管理-触发器 触发器会在指定的数据库事件发生时自动执行函数。 42.1 语法格式 创建触发器 CREATE TRIGGER trigger_name { BEFORE…

Java8实战-总结16

Java8实战-总结16 引入流流与集合只能遍历一次外部迭代与内部迭代 引入流 流与集合 只能遍历一次 和迭代器类似&#xff0c;流只能遍历一次。遍历完之后&#xff0c;这个流就已经被消费掉了。可以从原始数据源那里再获得一个新的流来重新遍历一遍&#xff0c;就像迭代器一样…

使用qsqlmysql操作mysql提示Driver not loaded

环境: win10 IDE: qt creator 编译器: mingw32 这里简单的记录下。我遇到的情况是在IDE使用debug和release程序都是运行正常&#xff0c;但是当我编译成发布版本之后。老是提示Driver not load。 这就很奇诡了。 回顾了下编译的时候是需要在使用qt先编译下libqsqlmysql.dll的…

从入门到精通Python隧道代理的使用与优化

哈喽&#xff0c;Python爬虫小伙伴们&#xff01;今天我们来聊聊如何从入门到精通地使用和优化Python隧道代理&#xff0c;让我们的爬虫程序更加稳定、高效&#xff01;今天我们将对使用和优化进行一个简单的梳理&#xff0c;并且会提供相应的代码示例。 1. 什么是隧道代理&…

V2board缓存投毒漏洞复现

1.什么是缓存投毒 缓存投毒&#xff08;Cache poisoning&#xff09;&#xff0c;通常也称为域名系统投毒&#xff08;domain name system poisoning&#xff09;&#xff0c;或DNS缓存投毒&#xff08;DNS cache poisoning&#xff09;。它是利用虚假Internet地址替换掉域名系…