当前位置: 首页 > news >正文

代理和AOP

一:java代理

整体分为两种:静态代理和动态代理
静态代理:23种设计模式里面有个代理模式,那个就是静态代理。
动态代理:分为编译时增强(AspectJ)和运行时增强(JDK动态代理和CGLIB动态代理)

1:静态代理

   这种代理在我们日常生活中其实非常常见,例如房屋中介就相当于是一个代理,当房东需要出租房子的时候,需要发布广告、寻找客户、清理房间。。。由于比较麻烦,因此房东可以将租房子这件事情委托给中间代理去做。这就是一个静态代理。我通过一个简单的代码来演示一下,首先我们有一个租房的接口,如下:

public interface Rent {void rent();
}

房东实现了该接口,想要出租房屋:

/*** 房东*/
public class Loadlord implements Rent{@Overridepublic void rent() {System.out.println("房屋出租");}
}

中介作为中间代理,也实现了该接口,同时代理了房东,如下:

public class HouseAgent implements Rent{private Loadlord loadlord;public HouseAgent(Loadlord loadlord) {this.loadlord = loadlord;}@Overridepublic void rent() {published();loadlord.rent();agentFee();}private void published(){System.out.println("发布广告");}private void agentFee(){System.out.println("收取中介费");}
}

可以看到,中介的 rent 方法中,除了调用房东的rent方法之外,还调用了 publishAd 和agencyFee两个方法。

接下来客户租房,只需要和代理打交道就行。如下:

/*** 静态代理demo*/
public class StaticDemo {public static void main(String[] args) {HouseAgent houseAgent = new HouseAgent(new Loadlord());houseAgent.rent();//输出:发布广告//     房屋出租//     收取中介费}
}

这就是简单的代理模式。

2:动态代理

    动态代理讲究在不改变原类原方法的情况下,增强目标方法的功能,例如,大家平时使用的Spring 事务功能,在不改变目标方法的情况下,就可以通过动态代理为方法添加事务处理能力。日志处理、接口幂等性处理、多数据源处理等,都是动态代理能力的体现。
例如,我有一个转账的业务:

public class MoneyService{public void transferMoney(){System.out.println("执行转账操作");} 
}

如果通过动态代理来为上面的业务代码添加事务,那么我们只需要做一些配置,系统会自动生成动态代理的类和方法:

public class MoneyServiceProxy{public void transferMoney() {try {//开启事务//执行事务//提交事务}catch (Exception e){//回滚事务}}}

上面这个是自动生成的代理类,不需要开发者开发。

从实现原理上来看又分为两类:编译时增强,运行时增强。

2.1:编译时增强

    编译时增强,这种有点类似于 Lombok的感觉,就是在编译阶段就直接生成了代理类,将来运行的时候,就直接运行这个编译生成的代理类,AspectJ就是这样一种编译时增强的工具。
    AspectJ 全称是 Eclipse AspectJ,其官网地址是:http://www.eclipse.or g/aspectj ,截止到本文写作时,目前最新版本为:1.9.7。从官网我们可以看到AspectJ的定位:

  1. 基于 Java 语言的面向切面编程语言
  2. 兼容 Java。
  3. 易学易用。

使用 AspectJ 时需要使用专门的编译器ajc。

编译时增强配置:
     首先在idea里面运行AspectJ,需要先安装AspectJ插件,如下:
在这里插入图片描述
安装好之后我们需要在idea中配置一下,使用ajc编译器代替javac:
在这里插入图片描述
有如下几个需要修改的点:

  1. 首先修改编译器为ajc。
  2. 将使用的 Java 版本改为8,这个一共有两个地方需要修改。
  3. 设置 aspectjtools.jar 的位置,这个jar 包需要自己提前准备好,可以从Maven 官网下载,然后在这里配置jar的路径,配置完成之后,点击test 按钮进行测试,测试成功就会弹出来图中的弹框。

对于第 3 步所需要的jar,也可以在项目的Maven中添加如下依赖,自动下载,下载到本地仓库之后,再删除掉 pom.xml 中的配置即可:

<dependency><groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId><version>1.9.7.M3</version> 
</dependency>

这样开发环境就准备好了。

接下来,假设我有一个银行转帐的方法:

public class MoneyService {public void transferMoney(){System.out.println("转账操作");} 
}

我想给这个操作添加事务,那么我就添加一个Aspect,如下:

public aspect TxAspect {void around( ):call(void MoneyService.transferMoney()){System.out.println("开启事务");try{proceed();System.out.println("提交事务事务");} catch (Exception e){System,out.println("回滚事务");}}}

这就是 AspectJ的语法,跟Java有点像,但是不太一样。需要注意的是,这个 TxAspect 不是一个 Java类,它的后缀是.aj。
proceed 表示继续执行目标方法,前后逻辑比较简单,我就不多说了。
最后我们去运行转帐服务:

public class Demo01{public static void main(String[] args) {MoneyService moneyService = new MoneyService();moneyService.transferMoney();}}

运行结果如下:
在这里插入图片描述
这就是一个静态代理

实际编译后底层代码如下(所以代码包括main方法也变了):
在这里插入图片描述
最后执行的都是修改之后的内容。所以说 AspectJ的作用就有点类似于Lombok,直接在编译时期将我们的代码改了,这就是编译时增强

2.2:运行时增强

    运行时增强则是指借助于JDK动态代理或者 CGLIB 动态代理等,在内存中临时生成 AOP 动态代理类,我们在Spring AOP 中常说的动态代理,一般是指这种运行时增强。
我们平日开发写的Spring AOP,基本上都是属于这一类。

1:JDK动态代理

    这个代理有一个要求就是,被代理的对象必须要有一个接口,没有接口不行。但是CGLIB没有这个要求。

假如我有一个计算机接口:

public interface ICalculator {int add(int a,int b);
}

这个接口有个实现类:

public class CalculatorImpl implements ICalculator{@Overridepublic int add(int a, int b) {System.out.println("a+b最终输出:"+(a+b));return a+b;}
}

现在我想实现统计该接口执行时间的功能,JDK动态代理如下:

public class Demo2 {/***** 下面生成的 calculator 是一个代理对象,注意,这个 calculator 对象并不是 CalculatorImpl 的对象** 相当于,在代码运行的过程中,自动生成了一个代理类:** public CalculatorProxy implements ICalculator{*     int add(int a,int b){*         long startTime = System.currentTimeMillis();*         //这个地方调用了 CalculatorImpl 类的实例的 add 方法,去执行了真正的 add 操作*         long endTime = System.currentTimeMillis();*         System.out.println(method.getName() + " 方法执行耗时 " + (endTime - startTime) + " 毫秒");*         return invoke;*     }* }** 最后,我们调用 calculator.add 方法的时候,其实执行的是这个代理的对象的 add 方法**/public static void main(String[] args) {CalculatorImpl calculatorImpl = new CalculatorImpl();//第二个参数表示生成的代理对象要实现哪些接口ICalculator calculator = (ICalculator) Proxy.newProxyInstance(Demo2.class.getClassLoader(), new Class[]{ICalculator.class}, new InvocationHandler() {/*** @param proxy 当前代理对象* @param method 被拦截下来的方法* @param args 被拦截下来的方法参数** @return 被拦截下来的方法的返回值* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();Object invoke = method.invoke(calculatorImpl, args);long endTime = System.currentTimeMillis();System.out.println(method.getName() + " 方法执行耗时 " + (endTime - startTime) + " 毫秒");return invoke;}});System.out.println("calculator.getClass() = " + calculator.getClass());calculator.add(3, 4);}
}

不需要任何额外依赖,都是JDK 自带的能力:
1.Proxy.newProxyInstance方法表示要生成一个动态代理对象。
2.newProxylnstance方法有三个参数,第一个是一个类加载器,第二个参数是一个被代理的对象所实现的接口,第三个则是具体的代理逻辑。
3.在 InvocationHandler 中,有一个 invoke 方法,该方法有三个参数,分别表示当前代理对象,被拦截下来的方法以及方法的参数,我们在该方法中可以统计被拦截方法的执行时间,通过方式执行被拦截下来的目标方法。
4.最终,第一步的方法返回了一个代理对象,执行该代理对象,就有代理的效果了。上面这个案例就是一个JDK动态代理。这是一种运行时增强,在编译阶段并未修改我们的代码。

2:CGLIB动态代理

    从SpringBoot2 开始,AOP 默认使用的动态代理就是CGLIB动态代理了,相比于 JDK 动态代理,CGLIB动态代理支持代理一个类。使用 CGLIB 动态代理,需要首先添加依赖,如下:

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

假设我有一个计算器,如下:

这个没有接口

public class Calculator {int minus(int a, int b) {System.out.println(a + "-" + b + "=" + (a - b));return a - b;}
}

随后在添加一个拦截器

public class CalculatoProxy implements MethodInterceptor {/*** 这个就是拦截器,将来 org.javaboy.demo.Calculator#minus(int, int) 方法执行的时候,这个拦截器会被触发,额外的工作就可以在这个方法中完成** @param o           代理对象* @param method      代理方法* @param objects     方法的参数* @param methodProxy 方法的代理对象* @return 拦截下来的方法的返回值* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {long startTime = System.currentTimeMillis();//相当于调用父类的方法,因为 CGLIB 动态代理,相当于给当前类生成了一个子类,在子类中添加了额外的逻辑Object result = methodProxy.invokeSuper(o, objects);long endTime = System.currentTimeMillis();System.out.println(method.getName() + " 方法执行耗时 " + (endTime - startTime) + " 毫秒");return result;}
}

通过methodProxy.invokeSuper(o, objects);调用到代理方法,最后如下配置CGLIB为方法增强

public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Calculator.class);enhancer.setCallback(new CalculatoProxy());Calculator calculator = (Calculator) enhancer.create();System.out.println("calculator.getClass() = " + calculator.getClass());calculator.minus(3, 4);}

    这里其实就是创建了字节增强器,为生成的代理对象配置superClass,然后设置拦截下来之后的回调函数就行了,最后通过create方法获取到一个代理对象。这就是 CGLIB 动态代理。

    Spring AOP 底层,本质上就是JDK 动态代理和CGLIB动态代理(运行时增强),它会根据我们的配置,自动去创建代理对象,可以做到零侵入。但是,这并不意味着Spring AOP 就脱离了 AspectJ,实际上,Spring AOP 中还是需要用到 AspectJ,只不过,Spring AOP使用的是 AspectJ中的一些注解,如@Apsect、@Before、@Pointcut 等,并没有使用AspectJ中的编译时增强。因此大家会发现,我们在使用Spring AOP 中,也需要添加AspectJ相关的依赖。

如果有接口但是也想用CGLIB有java方式和xml(xml有两种)方式,如下代码:

xml第一种方式:

<aop:aspectj-autoproxy proxy-target-class="true"/>

xml第二种方式:

<aop:config proxy-target-class="true"><aop:pointcut id="pc1" expression="execution(* com.richfit.richfit.service.XqyServiceImpl.*(..))"/><aop:aspect ref="logAdvice"><aop:before method="before" pointcut-ref="pc1"/><aop:after method="after" pointcut-ref="pc1"/><aop:after-throwing method="exception"  throwing="e" pointcut-ref="pc1"/><aop:after-returning method="returnAdvice"  returning="object" pointcut-ref="pc1"/><aop:around method="around" pointcut-ref="pc1"/></aop:aspect></aop:config>

上面主要是:

<aop:config proxy-target-class="true">

java方式

 @Aspect@Component
//这个相当于 <aop:aspectj-autoproxy/>,这个注解是用来识别项目中的 Aspect 的
@EnableAspectJAutoProxy(proxyTargetClass =true) 
public class LogAspect {}

二:Spring AOP 和 AspectJ AOP

Spring AOP 和 AspectJ AOP 是两种完全不同的 AOP实现。

2.1:Spring AOP

Spring AOP 是 Spring 框架中的 AOP 实现,依赖于 Spring 框架,要结合 Spring Bean 才能使用。Spring AOP是基于动态代理实现的,它的逻辑是这样,如果被代理的对象有接口,Spring AOP底层就会使用JDK动态代理;如果被代理的对象没有接口,那么Spring AOP底层就会使用CGLIB 动态代理。Spring AOP关注的点主要是方法级别的内容,即只能增强方法。
由于Spring AOP底层是动态代理,而动态代理底层是JDK动态代理或者 CGLIB动态代理(动态代理相当于生成了一个子类),所以,这就意味着如果方法或者类是 final 的,或者方法是static 的,都会导致动态代理失效(AOP失效),其实这也是 Spring 事务失效的原因

2.2:AspectJ AOP

AspectJ AOP 是一个完整的、独立的、并且功能十分强大的AOP解决方案,
Spring AOP 只能增强方法,而AspectJ AOP 不仅能增强方法,还能增强属性、构造器、static 方法、final 类、final 方法、private方法等等,都能增强。AspectJ AOP 是编译时增强,所以性能也要高于Spring AOP(当然,它也支持运行时增强)。

Spring AOP 虽然在多项数据上落后于AspectJ AOP,但是Spring AOP简单易用易上手,所以开发中还是以Spring AOP为主。

三:Spring AOP核心概念

Target/目标对象:被拦截下来的对象/要被增强的对象,如前面MoneyService、 Calculator 都是。

Join Point/连接点:可以被切面插入的地方,方法调用、异常抛出等。被切面增强的连接点。

PointCut/切点:被切面增强的连接点。

Advice/通知/增强:切点在连接处执行的代码,其实就是把目标方法拦截下来之后,要做的事情。

Aspect/切面:切点+通知。

Weaving/织入:将 Aspect应用到Target 的过程,就是Weaving。

Introduction/引介:为 target增强属性和方法。

四:AOP做日志通知(xml配置,基于springboot项目):

首先有一个aopadvice-spring.xml 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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--加载aopadvice-spring.xml 步骤:https://pythonjishu.com/uwrtruqtkjkhjud/本项目需要的类:LogAdvicexml:aopadvice-spring.xmlapplication.properties中加spring.config.name=aopadvice-springspring.config.location=classpath:/启动类里面加:@ImportResource("classpath:aopadvice-spring.xml")--><bean class="com.richfit.richfit.bootConfig.AopLog.LogAdvice" id="logAdvice"/><aop:config><aop:pointcut id="pc1" expression="execution(* com.richfit.richfit.service.XqyServiceImpl.*(..))"/><aop:aspect ref="logAdvice"><aop:before method="before" pointcut-ref="pc1"/><aop:after method="after" pointcut-ref="pc1"/><aop:after-throwing method="exception"  throwing="e" pointcut-ref="pc1"/><aop:after-returning method="returnAdvice"  returning="object" pointcut-ref="pc1"/><aop:around method="around" pointcut-ref="pc1"/></aop:aspect></aop:config>
</beans>

之后application.properties

spring.config.name=aopadvice-spring
spring.config.location=classpath:/

最后在启动类上加@ImportResource(“classpath:aopadvice-spring.xml”)即可。

相关文章:

代理和AOP

一:java代理 整体分为两种&#xff1a;静态代理和动态代理 静态代理&#xff1a;23种设计模式里面有个代理模式&#xff0c;那个就是静态代理。 动态代理&#xff1a;分为编译时增强(AspectJ)和运行时增强(JDK动态代理和CGLIB动态代理) 1:静态代理 这种代理在我们日常生活中其…...

Solidity-3-类型

Solidity 是一种静态类型语言&#xff0c;这意味着每个变量&#xff08;状态变量和局部变量&#xff09;都需要在编译时指定变量的类型。 “undefined”或“null”值的概念在Solidity中不存在&#xff0c;但是新声明的变量总是有一个 默认值 &#xff0c;具体的默认值跟类型相…...

【mask转json】文件互转

mask图像转json文件 当只有mask图像时&#xff0c;可使用下面代码得到json文件 import cv2 import os import json import sysdef func(file:str) -> dict:png cv2.imread(file)gray cv2.cvtColor(png, cv2.COLOR_BGR2GRAY)_, binary cv2.threshold(gray,10,255,cv2.TH…...

华清远见嵌入式学习——ARM——作业1

要求&#xff1a; 代码&#xff1a; mov r0,#0 用于加mov r1,#1 初始值mov r2,#101 终止值loop: cmp r1,r2addne r0,r0,r1addne r1,r1,#1bne loop 效果&#xff1a;...

如何在公网环境使用固定域名远程访问内网BUG管理系统协同办公

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…...

k8s pod网络排查教程

1、背景 背景&#xff1a;在日常的k8s运维中&#xff0c;经常会遇到pod之间网络无法访问&#xff0c;域名无法解释的情况。且容器中网络排查命令不全&#xff0c;导致无法准确定位问题。 2、nsenter介绍 #Centos 下载方式 $ yum install util-linux -ynsenter 是一个 Linux …...

Apollo Planning——换道:LANE_CHANGE_DECIDER

LaneChangeDecider 是lanefollow 场景下&#xff0c;所调用的第一个task&#xff0c;它的作用主要有两点&#xff1a;判断当前是否进行变道&#xff0c;以及变道的状态&#xff0c;并将结果存在变量lane_change_status中&#xff1b;变道过程中将目标车道的reference line放置到…...

Python 爬虫之简单的爬虫(三)

爬取动态网页&#xff08;上&#xff09; 文章目录 爬取动态网页&#xff08;上&#xff09;前言一、大致内容二、基本思路三、代码编写1.引入库2.加载网页数据3.获取指定数据 总结 前言 之前的两篇写的是爬取静态网页的内容&#xff0c;比较简单。接下来呢给大家讲一下如何去…...

为突发事件提供高现势性数据支撑!大势智慧助力中山市2023应急测绘保障演练举行

12月14日&#xff0c;2023年度中山市应急测绘保障演练在中山树木园举行&#xff0c;市自然资源局总工程师邓宇文出席本次演练活动。来自全市自然资源、应急管理部门和部分测绘单位的近70人现场观摩了演练。本次演练由中山市自然资源局主办、中山市自然资源信息中心承办&#xf…...

图片速览 OOD用于零样本 OOD 检测的 CLIPN:教 CLIP 说不

PAPERCODEhttps://arxiv.org/pdf/2308.12213v2.pdfhttps://github.com/xmed-lab/clipn 文章创新 以往由CLIP驱动的零样本OOD检测方法&#xff0c;只需要ID的类名&#xff0c;受到的关注较少。 本文提出了一种新的方法&#xff0c;即CLIP说“不”&#xff08;CLIPN&#xff09;…...

a16z:加密行业2024趋势“无缝用户体验”

近日&#xff0c;知名加密投资机构a16z发布了“Big ideas 2024”&#xff0c;列出了加密行业在 2024 年几个具备趋势的“大想法”&#xff0c;其中 Seamless UX&#xff08;无缝用户体验&#xff09;赫然在列。 从最为直观的理解上&#xff0c;Seamless UX 是在强调用户在使用产…...

C# WPF上位机开发(属性页面的设计)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在软件开发中&#xff0c;属性或者参数设置是很重要的一个部分。这个时候如果不想通过动态添加控件的方法来处理的话&#xff0c;那么可以通过tab控…...

macOS 安装 oh-my-zsh 后 node 报错 command not found : node

最近为了让终端中显示 git 分支的名称&#xff0c;安装了 oh-my-zsh &#xff0c;安装之后呢&#xff0c;我原先安装的 Volta、 node 都没法用了&#xff0c;报错如下&#xff1a; 这时候粗略判断应该是系统变量出了问题&#xff0c;oh-my-zsh 的变量文件是 ~/.zshrc&#xff0…...

AI 绘画 | Stable Diffusion 视频数字人

前言 本篇文章教会你如何利用Stable Diffusion WEB UI,使用一个人物图片转换成为一个口播视频。本篇内容的教程以WINDOWS系统为例,教你如何安装使用。 先看视频效果 彭于晏图片生成口播视频 安装 首先需要在windows电脑上安装ffmpeg,按照本教程《在 Windows PC 上轻松下载并…...

《代码随想录》--二叉树(一)

《代码随想录》--二叉树 第一部分 1、二叉树的递归遍历2、二叉树的迭代遍历3、统一风格的迭代遍历代码4、二叉树的层序遍历226.翻转二叉树 1、二叉树的递归遍历 前序遍历 中序遍历 后序遍历 代码 前序遍历 class Solution {public List<Integer> preorderTraversal(T…...

shell编程-数组与运算符详解(超详细)

文章目录 前言一、 Shell数组1. 声明和初始化数组2. 访问数组元素3. 数组长度4. 遍历数组5. 修改数组元素6. 删除数组元素7. 示例 二、Shell运算符1. 算术运算符1.1 加法运算符 ()1.2 减法运算符 (-)1.3 乘法运算符 (*)1.4 除法运算符 (/)1.5 取余运算符 (%) 2. 关系运算符2.1 …...

Vim入门

Vim使用入门 1.Vim编辑器的三种常用模式 一般模式&#xff1a;刚打开文件是它&#xff0c;从编辑模式按“ESC”退回的模式也是它。可以执行各种编辑操作&#xff0c;如移动光标、复制、粘贴、删除、查找替换等 ; 编辑模式&#xff1a;在一般模式下按下 i、I、a、A、o、O 等键…...

动态加载库

no_mangle 不要改标识符 首先是认识这个标注&#xff1a;mangle&#xff0c;英文的含义“撕裂、碾压”。我第一次把这个单次误以为是manage&#xff0c;说实话两个单词还挺像的。 RUS中函数或静态变量使用#[no_mangle]这个标注属性后&#xff0c;编译器就不会修改它们的名字了…...

React中渲染html结构---dangerouslySetInnerHTML

dangerouslySetInnerHTML胡子{}语法绑定的内容全部作为普通文本渲染&#xff0c;渲染html结构基于---dangerouslySetInnerHTMLdangerouslySetInnerHTML是React标签的一个属性&#xff0c;类似于vue的v-html有2个{{}},第一个{}代表jsx语法开始&#xff0c;第二个是代表dangerous…...

计网02-计算机网络参考模型

一、OSI七层参考模型 1、分层的思想 分层模型用于网络协议的设计方法&#xff0c;本质是将网络节点间复杂的通信问题分成若干简单的问题逐一解决&#xff0c;通过网络的层次去找问题&#xff0c;将复杂问题简单化。 2、OSI参考模型 由于早期计算机厂商使用的是私有的网络模…...

模块测试:确保软件质量的关键步骤

引言&#xff1a; 在软件开发过程中&#xff0c;模块测试是确保软件质量的关键环节。通过模块化的设计和测试方法&#xff0c;可以提高开发效率、降低错误率&#xff0c;并最终提供稳定可靠的软件产品。本文将介绍模块测试的概念、重要性以及实施步骤&#xff0c;帮助读者了解如…...

Postman接口测试之Postman常用的快捷键

作为一名IT程序猿&#xff0c;不懂一些工具的快捷方式&#xff0c;应该会被鄙视的吧。收集了一些Postman的快捷方式&#xff0c;大家一起动手操作~ 简单操作 xc 请求 操作MAC系统windows系统请求网址 ⌘L Ctrl L 保存请求 ⌘S Ctrl S 保存请求为 ⇧⌘S Ctrl Shift S发送…...

keil自动分配SDRAM空间设置使用

1.修改.sct文件 添加 RW_RAM1 0xC0400000 UNINIT 0x00400000 { ; RW data .ANY (SD_RAM1) 使用 #define LOCATION_ATTRIBUTE(name) __attribute__ ((section(name))) __attribute__ ((aligned(4)))uint8_t sdram_buf[0x100000] __attribute__ ((section("SD_RAM1")…...

TikTok获客怎么做?可以定制一个获客工具!

随着社交媒体的兴起&#xff0c;越来越多的企业开始将目光投向了短视频平台&#xff0c;TikTok作为其中的佼佼者&#xff0c;凭借其独特的算法和内容推荐机制&#xff0c;吸引了大量用户的关注。 那么&#xff0c;如何在TikTok上获取更多的客户呢?本文将为您揭秘TikTok获客的…...

数据结构(Chapter Two -02)—顺序表基本操作实现

在前一部分我们了解线性表和顺序表概念&#xff0c;如果有不清楚可以参考下面的博客&#xff1a; 数据结构(Chapter Two -01)—线性表及顺序表-CSDN博客 首先列出线性表的数据结构&#xff1a; #define MaxSize 50 //定义顺序表最大长度 typedef struct{ElemType data…...

SQL语句整理二--Mysql

文章目录 知识点梳理&#xff1a;1. mysql 中 in 和 exists 区别2. varchar 与 char 的区别 查看表结构&#xff1a;获取当前时间&#xff1a;查看建表语句&#xff1a;修改用户密码&#xff1a;查看所有用户&#xff1a;grant命令&#xff1a;判断当前数据库有多少连接数&…...

oracle与gbase8s迁移数据类型对照

声明&#xff1a;以下为笔者阅读gbase官方文档和oracle官方文档的理解&#xff0c;如有错误&#xff0c;敬请指正。oracle与gbase8s迁移数据类型对照及举例说明 最终结论&#xff1a;oracle与gbase8s数据类型对应关系关于单精度与双精度的区别关于定点与浮点定义的区别精度的定…...

Flink系列之:集合操作

Flink系列之&#xff1a;集合操作 一、集合操作二、UNION三、INTERSECT四、EXCEPT五、IN六、EXISTS 一、集合操作 适用于流、批操作 二、UNION UNION 和 UNION ALL 返回两个表中的数据。 UNION 会去重&#xff0c;UNION ALL 不会去重。 Flink SQL> create view t1(s) as…...

STL:string的常见用法

目录 赋值和连接&#xff1a; operator: 赋值操作符&#xff1a; assign(str): 将字符串赋值为另一个字符串&#xff1a; : 字符串连接操作符&#xff1a; 访问和检查&#xff1a; at(pos): 返回指定位置的字符&#xff0c;提供边界检查。 operator[]: 返回指定位置的字符…...

GBASE南大通用 ADO.NET 中的事务

GBASE南大通用 ADO.NET 中支持事务&#xff0c;可以使用GBASE南大通用Connection 对象的BeginTransaction 函数开始一个事务&#xff0c;并默认使用 ReadCommitted 模式初始化。 事务中可以对单个表执行多个操作&#xff0c;或者对多个表执行多个操作&#xff0c;在事务未提交…...