SpringAOP入门基础银行转账实例(进阶版)------------事务处理

news2024/11/24 20:04:05

SpringAOP入门基础银行转账实例**(进阶版)**------------事务处理

由上一节讲述的通过Connection和QueryRunner对事务进行的处理(详情可以去我之前写的博客文章:https://blog.csdn.net/m0_56245143/article/details/130069160?spm=1001.2014.3001.5501查看)

接下来由我们将对它进行简单的AOP改造

我们还是沿用上次的项目模块:
在这里插入图片描述

Spring基于配置文件的AOP

环境搭建

对该项目进行maven工程添加依赖:pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>7</source>
                    <target>7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <groupId>com.etime</groupId>
    <artifactId>day05</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>5.2.5.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!--导入spring的context坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--导入Jdbc模块依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--   DBUtils    -->
        <!--        <dependency>-->
        <!--            <groupId>commons-dbutils</groupId>-->
        <!--            <artifactId>commons-dbutils</artifactId>-->
        <!--            <version>1.6</version>-->
        <!--        </dependency>-->

        <!-- 数据库相关 -->
        <!--        <dependency>-->
        <!--            <groupId>mysql</groupId>-->
        <!--            <artifactId>mysql-connector-java</artifactId>-->
        <!--            <version>5.1.6</version>-->
        <!--        </dependency>-->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!--c3p0-->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

<!--        添加测试依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

<!--        dbutils依赖的添加-->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>

<!--        添加aop配置依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
    </dependencies>
</project>

创建Spring的配置文件并导入约束

准备的资源:需要扫描当前项目包下的com.etime、需要配置文件内的连接数据库的基本资源、以及导入数据库连接的约束、配置JdbcTemplate模块

application.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--    扫描包-->
    <context:component-scan base-package="com.etime"></context:component-scan>

    <!--加载属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--数据源对象-->
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--    配置JdbcTemplate模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="ds"/>
    </bean>

<!--    加载QueryRunner-->
    <bean id="qr" class="org.apache.commons.dbutils.QueryRunner"></bean>

<!--    配置切面-->
<!--    <aop:config>-->
<!--        <aop:aspect id="tm" ref="transactionUtil">-->
<!--&lt;!&ndash;            配置切面点&ndash;&gt;-->
<!--&lt;!&ndash;            配置com.etime.service.impl包下的AccountServiceImpl类中的transferAccount方法&ndash;&gt;-->
<!--            <aop:pointcut id="po" expression="execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))"/>-->
<!--&lt;!&ndash;            开始事务&ndash;&gt;-->
<!--&lt;!&ndash;            <aop:before method="startTransaction" pointcut-ref="po"></aop:before>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash;            提交事务&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash;            <aop:after-returning method="commitTransaction" pointcut-ref="po"></aop:after-returning>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash;            出现错误回滚&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash;            <aop:after-throwing method="rollBackTransaction" pointcut-ref="po"></aop:after-throwing>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash;            关闭事务&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash;            <aop:after method="closeTransaction" pointcut-ref="po"></aop:after>&ndash;&gt;-->
<!--            <aop:around method="transactionAround" pointcut-ref="po"></aop:around>-->
<!--        </aop:aspect>-->
<!--    </aop:config>-->
<!--&lt;!&ndash;    开启spring对注解AOP的支持&ndash;&gt;-->
<!--&lt;!&ndash;    <aop:aspectj-autoproxy/>&ndash;&gt;-->

<!--&lt;!&ndash;    配置事务管理器&ndash;&gt;-->
<!--    <bean id="dtm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">-->
<!--        <property name="dataSource" ref="ds"></property>-->
<!--    </bean>-->

<!--&lt;!&ndash;    配置事务的通知引用事务管理器&ndash;&gt;-->
<!--&lt;!&ndash;    在tx:advice中配置事务的属性&ndash;&gt;-->
<!--    <tx:advice id="d" transaction-manager="dtm">-->
<!--        <tx:attributes>-->
<!--            <tx:method name="*"/>-->
<!--        </tx:attributes>-->
<!--    </tx:advice>-->

<!--&lt;!&ndash;    配置AOP切入点表达式&ndash;&gt;-->
<!--    <aop:config>-->
<!--        <aop:pointcut id="point" expression="execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))"/>-->
<!--&lt;!&ndash;        在aop:config标签内部:建立事务通知和切入点表达式的关系&ndash;&gt;-->
<!--        <aop:advisor advice-ref="d" pointcut-ref="point"></aop:advisor>-->
<!--    </aop:config>-->
</beans>

创建ConnectionUtil.java完成连接的反转控制

ConnectionUtil.java

package com.etime.util;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import sun.rmi.transport.Connection;

@Component("connection")
public class ConnectionUtil {
//    @Autowired
//    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ComboPooledDataSource ds;

    @Bean(name = "connection")
    public Connection getConnection() throws Exception {
        return (Connection) ds.getConnection();
    }
}

AOP配置

使用aop:config声明AOP配置

aop:config:

​		作用:开始声明aop配置

< aop:config >

​			配置的代码

< /aop:config >

在这里插入图片描述

使用aop:aspect配置切面

aop: aspect

​		作用:用于配置切面

​		属性:

​				id:给切面提供一个唯一标识

​				ref:引用配置好的通知类bean的id

​				<aop:aspect id="tm" ref="transactionUtil">

​					...

​				< /aop:aspect>

使用aop:pointcut配置切入点表达式

aop:pointcut

作用:用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。

属性:expression:用于定义切入点表达式。

​			id:用于切入点表达式提供一个唯一标识

< aop : poincut id="po" expression="execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))"/>

使用aop:xx配置对应的通知类型

aop:before

作用:用于配置前置通知。指定增强的方法在切入点方法之前执行

属性:

method:用于指定通知类中的增强方法名称

ponitcut-ref:用于指定切入点的表达式的引用

ponitcut:用于指定切入点表达式

执行时间点:

切入点方法执行之前执行

<aop:before method="startTransaction" pointcut-ref="po" ></aop:before >
aop:after-returning
	作用: 
    	用于配置后置通知
	属性:
   		method:指定通知中方法的名称。
  		pointct:定义切入点表达式
   		pointcut-ref:指定切入点表达式的引用
   	执行时间点:
   	    切入点方法正常执行之后。它和异常通知只能有一个执行
        <aop:after-returning method="commitTransaction" pointcut-ref="po"></aop:after-returning > 
aop:after-throwing
	作用:
		用于配置异常通知
	属性:
		method:指定通知中方法的名称。
		pointct:定义切入点表达式
		pointcut-ref:指定切入点表达式的引用
	执行时间点:
		切入点方法执行产生异常后执行。它和后置通知只能执行一个
        <aop:after-throwing method="rollBackTransaction" pointcut-ref="po"></aop:after-throwing >
aop:after
	作用:
		用于配置最终通知
	属性:
        method:指定通知中方法的名称。
        pointct:定义切入点表达式
        pointcut-ref:指定切入点表达式的引用
	执行时间点:
		无论切入点方法执行时是否有异常,它都会在其后面执行。
   	    <aop:after method="closeTransaction" pointcut-ref="po"></aop:after >

application.xml

配置后的代码:

<!--    配置切面-->
    <aop:config>
        <aop:aspect id="tm" ref="transactionUtil">
<!--            配置切面点-->
<!--            配置com.etime.service.impl包下的AccountServiceImpl类中的transferAccount方法-->
            <aop:pointcut id="po" expression="execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))"/>
<!--            开始事务-->
            <aop:before method="startTransaction" pointcut-ref="po"></aop:before>
<!--            提交事务-->
            <aop:after-returning method="commitTransaction" pointcut-ref="po"></aop:after-returning>
<!--            出现错误回滚-->
            <aop:after-throwing method="rollBackTransaction" pointcut-ref="po"></aop:after-throwing>
<!--            关闭事务-->
            <aop:after method="closeTransaction" pointcut-ref="po"></aop:after>
<!--            <aop:around method="transactionAround" pointcut-ref="po"></aop:around>-->
        </aop:aspect>
    </aop:config>

service:修改

package com.etime.service.impl;

import com.etime.dao.AccountDao;
import com.etime.entity.Account;
import com.etime.service.AccountService;
import com.etime.util.TransactionUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;

@Service("as")
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

//    @Autowired
//    private TransactionUtil transactionUtil;

    //这里不能将此处的异常try,catch.spring只能捕捉throws的异常
    @Override
    public void transferAccount(String name1, String name2, double money) throws SQLException {
//        try {
//            //开启事务
//            transactionUtil.startTransaction();
            //收到的钱
            Account accountOne=accountDao.getByName(name1);
            accountOne.setMoney(accountOne.getMoney()+money);
            accountDao.updateAccount(accountOne);

            //钱转出
            Account accountTwo=accountDao.getByName(name2);
            accountTwo.setMoney(accountTwo.getMoney()-money);
            accountDao.updateAccount(accountTwo);

//            //以上数据没有数据操作错误,就提交
//            transactionUtil.commitTransaction();
//        }catch (SQLException e){
//            //如果数据有误,进行数据回滚
//            transactionUtil.rollBackTransaction();
//            e.printStackTrace();
//        }finally {
            //如果服务结束,事务关闭(不管是否服务成功都进行最后的事务关闭)
//            transactionUtil.closeTransaction();
//        }
    }
}

如图所示的运行结果:异常事务能正常处理

在这里插入图片描述

切点表达式说明

切点表达式的语法

execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号* 代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

例如:

全匹配方式

public void 
com.etime.service.impl.AccountServiceImpl.saveAccount(com.etime.domain.Account)

访问修饰符可以省略

void com.etime.service.impl.AccountServiceImpl.saveAccount(com.etime.domain.Account)

返回值可以使用*号,表示任意返回值

* com.etime.service.impl.AccountServiceImpl.saveAccount(com.etime.domain.Account)

包名可以使用 * 号,表示任意包,但是有几级包,需要写几个 *

* *.*.*.*.AccountServiceImpl.saveAccount(com.etime.domain.Account)

使用…来表示当前包,及其子包

* com..AccountServiceImpl.saveAccount(com.etime.domain.Account)

类名可以使用*号,表示任意类

* com..*.saveAccount(com.etime.domain.Account)

方法名可以使用*号,表示任意方法

* com..*.*(com.etime.domain.Account)

参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数

* com..*.*(*)

参数列表可以使用…表示有无参数均可,有参数可以是任意类型

* com..*.*(..)

全通配方式:

* *..*.*(..)

注意: 通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。

execution(* com.etime.service.impl.*.*(..))

环绕通知配置事务管理

在TransactionUtil类当中添加方法

/**
     * 环绕通知:
     * spring 框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数。
     * 在环绕通知执行时,spring 框架会为我们提供该接口的实现类对象,我们直接使用就行。
     * @param pjp
     * @return
     */
    //环绕通知方法
    public Object transactionAround(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            //获取调用切入点方法时传入的参数
            Object[] args = pjp.getArgs();
            startTransaction();
            //运行切入点方法
            result = pjp.proceed(args);
            commitTransaction();
        } catch (Throwable throwable) {
            rollbackTransaction();
            throwable.printStackTrace();
        } finally {
            closeConnection();
        }
        return result;
    }
 aop:around:
	作用:
		用于配置环绕通知
	属性:
        method:指定通知中方法的名称。
        pointct:定义切入点表达式
        pointcut-ref:指定切入点表达式的引用
	说明:
        它是 spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
        注意:通常情况下,环绕通知都是独立使用的
<!--    配置切面-->
    <aop:config>
        <aop:aspect id="tm" ref="transactionUtil">
<!--            配置切面点-->
<!--            配置com.etime.service.impl包下的AccountServiceImpl类中的transferAccount方法-->
            <aop:pointcut id="po" expression="execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))"/>
<!--            开始事务-->
<!--            <aop:before method="startTransaction" pointcut-ref="po"></aop:before>-->
<!--&lt;!&ndash;            提交事务&ndash;&gt;-->
<!--            <aop:after-returning method="commitTransaction" pointcut-ref="po"></aop:after-returning>-->
<!--&lt;!&ndash;            出现错误回滚&ndash;&gt;-->
<!--            <aop:after-throwing method="rollBackTransaction" pointcut-ref="po"></aop:after-throwing>-->
<!--&lt;!&ndash;            关闭事务&ndash;&gt;-->
<!--            <aop:after method="closeTransaction" pointcut-ref="po"></aop:after>-->
            <aop:around method="transactionAround" pointcut-ref="po"></aop:around>
        </aop:aspect>
    </aop:config>

运行结果:正常异常事务处理

在这里插入图片描述

Spring基于注解的AOP

AOP注解方式和XML方式完成的功能都是一样的,只是采用了两种开发方式而已。将原有的XML方式使用注解逐一替代。

接上一节所配置的环境

通知类使用注解配置和使用@Acpect注解声明为切面

在这里插入图片描述

在增强的方法上使用注解配置通知

@Before
	作用:
		把当前方法看成是前置通知
	属性:
		value:用于指定切入点表达式,还可以指定切入点表达式的引用。
    
    @Before("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public void startTransaction() {
        try {
            System.out.println("启动事务");
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }     
 @AfterReturning
	作用: 
		把当前方法看成是后置通知。
	属性: 
		value:用于指定切入点表达式,还可以指定切入点表达式的引用
		
    @AfterReturning("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public void commitTransaction() {
        try {
            System.out.println("提交");
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
@AfterThrowing
	作用: 
		把当前方法看成是异常通知。
	属性: 
		value:用于指定切入点表达式,还可以指定切入点表达式的引用
		
    @AfterThrowing("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public void rollBackTransaction() {
        try {
            System.out.println("回滚");
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
@After
	作用: 
		把当前方法看成是最终通知。
	属性: 
		value:用于指定切入点表达式,还可以指定切入点表达式的引用

    @After("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public void closeTransaction() {
        try {
            System.out.println("释放资源");
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

到这里由上述的配置后可以直接运行,也是同样对事务进行处理,这里我就不运行了,只是用注解的方式更加的简洁

环绕通知配置事务管理

在TransactionUtil类中添加环绕配置

@Around
	作用: 
		把当前方法看成是环绕通知。
	属性: 
		value:用于指定切入点表达式,还可以指定切入点表达式的引用。
        
    @Around("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public Object transactionAround(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            Object[] args = pjp.getArgs();
            startTransaction();
            result = pjp.proceed(args);
            commitTransaction();
        } catch (Throwable throwable) {
            rollbackTransaction();
            throwable.printStackTrace();
        } finally {
            closeConnection();
        }
        return result;
    }

加环绕配置

@Around
	作用: 
		把当前方法看成是环绕通知。
	属性: 
		value:用于指定切入点表达式,还可以指定切入点表达式的引用。
        
    @Around("execution(public void com.etime.service.impl.AccountServiceImpl.transferAccount(..))")
    public Object transactionAround(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            Object[] args = pjp.getArgs();
            startTransaction();
            result = pjp.proceed(args);
            commitTransaction();
        } catch (Throwable throwable) {
            rollbackTransaction();
            throwable.printStackTrace();
        } finally {
            closeConnection();
        }
        return result;
    }

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

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

相关文章

派盘为您的个人数据安家

现如今,我们的生活中有着各种各样的数据。在工作中会有各种文件、邮件;在生活中则有照片和视频等。数据的来源多,时间点不一致且混乱。 数据是否能安全、稳定、长久的存储以及便捷高效的使用对我们来说相当重要。你是否经常出差需要带上电脑或者移动硬盘,想存网盘又怕丢失或…

牛客网:HJ1 字符串最后一个单词的长度

题目部分&#xff1a; 解题思路&#xff1a; 方案一&#xff1a; 对于本题&#xff0c;看似简单&#xff0c;其实有坑。 就是在获取单词这块&#xff0c;不能直接用cin这样子操作&#xff0c;否则不能获取到完整的单词&#xff0c;因为cin这样的读到空格就不会往后续读了&…

elsticsearch与关系数据库的区别

查看所有索引&#xff08;表&#xff09; 向索引&#xff08;表&#xff09;中添加数据&#xff1a; 自定义id添加数据&#xff1a; 自定义id添加数据&#xff1a;方式二

Android12之网络共存

一.思路 所谓共存就是让两个网络同时使用,如果想让哪个网络作为外网,则该网络优先级要高于内网的网络,即可达到外网用来上网的需求,那么要想共存,就必须到从低优先级网络切换到优先级高的网络时,不要做断开操作,即可达到,两个网络同时存在的需求,做到以上两点,我们便…

MiniGPT4,开源了

简介 MiniGPT-4 旨在将来自预训练视觉编码器的视觉信息与先进的大型语言模型 (LLM) 对齐。 具体来说&#xff0c;在文本方面&#xff0c;作者利用 Vicuna 作为语言解码器&#xff0c;在视觉感知方面&#xff0c;使用了与BLIP-2相同的视觉编码器&#xff0c;并且语言和视觉模型…

数据结构(C语言实现)——二叉树的概念及二叉树顺序结构和链式结构的实现(堆排序+TOP-K问题+链式二叉树相关操作)

文章目录1. 前言2. 树的概念及结构2.1 树的概念2.2 树的相关概念2.3 树的表示3. 二叉树的概念3.1 特殊二叉树3.2 二叉树的性质4. 二叉树的顺序存储4.1 堆的概念4.2 堆的实现4.2.1 堆的结点定义4.2.2 堆的打印和销毁4.2.3 堆的插入4.2.4 堆的删除4.2.5 取堆顶数据4.2.6 堆的判空…

【Python学习笔记】cs231nPython Numpy教程

【Python学习笔记】cs231nPython Numpy教程 回顾经典教程cs231n&#xff0c;完成assignments觉得很困难&#xff0c;感觉自己python基础语法掌握的不是很熟&#xff0c;就顺藤摸瓜找了cs231n他们的官方Python个Numpy教程 如果对英文原版上手有困难&#xff0c;可以看这个&…

智慧园区水电监测系统

随着人们对环保意识的提高&#xff0c;智慧园区的建设也越来越受到关注。其中&#xff0c;水电监测系统是智慧园区的一个重要组成部分。本文将从以下几个方面介绍智慧园区水电监测系统的特点和优势。 一、智慧园区水电监测系统的特点 1.实时监测&#xff1a;智慧园区水电监测系…

某医院网络故障分析案例

1、背景 某市第一医院用户反馈&#xff0c;近期内部业务系统出现访问慢的情况&#xff0c;这种情况严重影响到用户的体验和工作效率。 针对此问题&#xff0c;我们通过NetInside流量分析系统&#xff0c;提供实时和历史原始流量。重点针对网络异常流量跟踪分析&#xff0c;找…

go数据结构(二叉树的遍历)

用数组来存储二叉树如何遍历的呢&#xff1f; 如果父节点的数组下表是i&#xff0c;那么它的左孩子就是i * 2 1&#xff0c;右孩子就是 i * 2 2。 二叉树的遍历方式&#xff1a; 二叉树有三种基本遍历方式&#xff0c;分别是前序遍历、中序遍历和后序遍历。遍历的原理是从根…

Jenkins 流水线

采用Jenkins的自由风格构建的项目&#xff0c;适合用于测试和学习&#xff0c;主要问题有&#xff1a; 构建过程中整体流程是不可见的&#xff0c;无法确认每个流程花费的时间出现问题不方便快速的定位无法进行版本化管理多个任务中有很多步骤需要重复搭建 Jenkins的Pipeline…

MYSQL Row 752 was cut by GROUP_CONCAT()

因为group_concat有个最大长度的限制&#xff0c;GROUP_CONCAT函数返回的结果大小被MySQL默认限制为1024(字节)的长度。超过最大长度就会被截断掉 解决方法&#xff1a;更改配置文件&#xff0c;修改长度。 https://blog.csdn.net/zzddada/article/details/115082236 concat…

DHCP与RIP配置实验

目录 一、实验要求与拓扑结构 1、实验要求 2、提前规划好网段的拓扑结构如下图 二、实验步骤 1、给每台路由器的各个接口配置ip 2、给路由器AR1和AR3配置dhcp服务 3、在路由器AR1和AR2上运行ripv2&#xff0c;在AR3上运行ripv1 4、更改接口的rip协议版本 一、实验要求与…

chatglm-6b模型在windows的详细安装教程

1.先是看了github的文章&#xff08;如果打不开这篇文章&#xff0c;可能需要科学上网&#xff0c;即访问外网的VPN&#xff09;&#xff1a; https://github.com/THUDM/ChatGLM-6B 2.准备&#xff1a;台式机&#xff0c;GPU是8G。&#xff08;关于是否可以在笔记本运行&#x…

【网路】-- HTTP协议

目录 HTTP协议 认识URL urlencode和urldecode Http http的宏观结构 http请求报文格式 http响应报文格式 HTTP的方法 表单 重定向 HTTP常见Header 会话管理 Cookie 实验证明 Connection选项 工具推荐 Fiddler 原理 应用层&#xff1a;就是程序员基于socket接口…

如何在大厂做好架构演进?

1 架构演进的定义 1.1 定义 通过设计新的系统架构(4R)&#xff0c;来应对业务和技术的发展变化。 1.2 关键点 新架构新的复杂度 1.3 目的 应对业务和技术的发展变化后带来新的复杂度。 案例 淘宝去IOE&#xff0c;是因为业务发展大了后&#xff0c;IOE的成本和可控性难…

51单片机入门

文章目录 一、安装keil5及proteus二、MCS-51单片机结构与原理(一).8051单片机基本组成(二).8051单片机引脚1.电源引脚2.时钟电路引脚3.控制信号引脚4.输入/输出端口 (三) 并行输入/输出端口结构 三、单片机cx51编程基础(一).变量定义(二).数据类型(三).存储类型(四).Cx51语言程…

【Python】逆向解析js代码

目录 1. 打开百度翻译网页&#xff0c;查找翻译结果的网络资源包 2. 获取翻译结果网络资源包的url、请求头、请求体&#xff0c;解析json文件数据 3. 观察请求体字段&#xff0c;发现 query 字段便是我们输入的需要翻译的值 4. ctrl F 快捷键搜索sign值的网络资源包&#x…

自然语言处理:词嵌入简介

动动发财的小手&#xff0c;点个赞吧&#xff01; Word Embeddings 机器学习模型“查看”数据的方式与我们&#xff08;人类&#xff09;的方式不同。例如&#xff0c;我们可以轻松理解“我看到一只猫”这一文本&#xff0c;但我们的模型却不能——它们需要特征向量。此类向量或…

MongoDB 聚合管道的集合关联($lookup)及合并($unionWith)

目前为止&#xff0c;我们已经介绍了一部分聚合管道中的管道参数&#xff1a; $match&#xff1a;文档过滤 $group&#xff1a;文档分组&#xff0c;并介绍了分组中的常用操作&#xff1a;$addToSet&#xff0c;$avg&#xff0c;$sum&#xff0c;$min&#xff0c;$max等。 $add…