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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VMware vSphere 8.0c - 企业级工作负载平台

ESXi 8.0.0 & vCenter Server 8.0.0 GA (General Availability) 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-vsphere-8/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2023-03-30, VMware vSphere 8.0c 发…

静态库与动态库

库是已经写好的、成熟的、可复用的代码。在我们的开发的应用中经常有一些公共代码是需要反复使用的&#xff0c;就把这些代码编译为库文件。库可以简单看成一组目标文件的集合&#xff0c;将这些目标文件经过压缩打包之后形成的一个可执行代码的二进制文件。库有两种&#xff1…

Ubuntu硬盘分区、挂载

文章目录1、使用命令查看硬盘情况2、分区3、格式化分区4、挂载手动挂载自动挂载1、使用命令查看硬盘情况 sudo fdisk -l 可以看到这里有个未分区的4T硬盘 如&#xff1a;sdb 这样的是硬盘 sdb1 sdb2 这样的是分区&#xff0c;现在还没分区 2、分区 sudo parted /dev/sdb (s…

一切都是命中注定的!

“光锥之内就是命运”&#xff0c;这是刘慈欣的《三体黑暗森林》里一句话&#xff0c;如果我们看到一件事情正在发生&#xff0c;那么它早在过去无论是几秒前还是几千年前&#xff0c;就已经发生了&#xff0c;我们无法改变这个命运。 孔明叹曰&#xff1a;“谋事在人&#xf…

树莓派通过网线连接笔记本实现笔记本电脑Wifi的网络共享

基于windows电脑连接树莓派进行设置&#xff1a;通过通过一根网线&#xff0c;连接树莓派和电脑&#xff0c;使电脑和树莓派构成一个局域网&#xff0c;然后树莓派接收来自笔记本电脑wifi网络的共享网络。操作方法类似台式机通过网线共享笔记本电脑无线网络的步骤 1、 保证笔记…

总结816

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 高等数学&#xff1a;一元积分&#xff0c;算是彻底过一遍了&#xff0c;但还是需要再回顾一遍。今日一道变限积分求导出…

简单的单目测距实验

一、原理 简单的单目测距方法&#xff0c;假设相机平面和物体平面平行&#xff0c;相机正对着物体表面拍摄&#xff0c;则可以利用相似三角形法。 用相似三角形计算物体或者目标到相机的距离&#xff0c;将使用相似三角形来计算相机到一个已知的物体或者目标的距离。 假设有…

执行数学的运算

数学是计算机编程的重要能力。遗憾的是&#xff0c;对shell脚本来说&#xff0c;这个处理过程比较麻烦。在shell脚本中两种途径来进行数学运算。 expr命令 最开始&#xff0c;Bourne shell提供了一个特别的命令用来处理数学表达式。expr命令允许在命令行上处理数学数学表达式。…

算法学习day59

算法学习day591.力扣503.下一个更大元素II1.1 题目描述1.2 分析1.3代码2.力扣42. 接雨水2.1 题目描述2.2 分析2.3 代码3.参考资料1.力扣503.下一个更大元素II 1.1 题目描述 题目描述&#xff1a; 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&a…

【Java 并发编程】一文了解线程间有哪些通信方式?

一文了解线程间有哪些通信方式&#xff1f;1. synchronized 内置锁2. volatile 关键字3. 等待/通知机制3.1 等待wait()wait(long)wait(long, int)等待方需遵循如下原则3.2 通知notify()notifyAll()通知方需遵循如下原则notify() 和 notifyAll() 应该用谁&#xff1f;4. 管道输入…

BusterNet网络Python模型实现学习笔记一

实在是无力吐槽了&#xff0c;心力交瘁。作者Github仓库给了错误的 USCISI-CMFD-Small 数据集。自己捣鼓了半天&#xff0c;发现原来是压缩之后数据集&#xff0c;也就是 LMDB 文件格式出错了。实在是误人子弟&#xff0c;自己已经气急败坏了现在… 但是既然论文都花那么长时间…

数据分析之Pandas 基础入门

一、初始Pandas pandas 是数据分析三大件之一&#xff0c;是Python的核心分析库&#xff0c;它提供了快捷、灵活、明确的数据结构&#xff0c;它能够简单、直观、快速的处理各种类型的数据结构。 pandas 支持的数据结构如下&#xff1a; SQL 或Excel 类似的数据有序或无序的…

【学习笔记】unity脚本学习(三)(向量 Vector3)

目录向量复习高中向量基础【数学】向量的四则运算、点积、叉积、正交基叉乘公式叉乘运算定理向量、坐标系点积叉积Vector3 三维向量静态变量变量变量normalized 与 Normalize() 方法静态方法ClampMagnitudeCrossDistanceDotMoveTowards其他变换类似Lerp 在两个点之间进行线性插…

实现一个简单但有趣的AR效果(Web)

有人说:一个人从1岁活到80岁很平凡,但如果从80岁倒着活,那么一半以上的人都可能不凡。 生活没有捷径,我们踩过的坑都成为了生活的经验,这些经验越早知道,你要走的弯路就会越少。

MySQL 库操作

目录 创建数据库 语法 案例 字符集和校验规则&#xff08;建数据库/建表用&#xff09; 查看系统默认字符集以及校验规则 db.opt 更改 查看数据库支持的字符集 查看数据库支持的字符集校验规则 校验规则对数据库的影响 排升序 操纵数据库 查看数据库 显示创建语…

洛谷P2822:组合数问题 ←(帕斯卡法则+取模+前缀和)

【题目来源】https://www.luogu.com.cn/problem/P2822https://www.acwing.com/problem/content/525/【题目描述】 组合数​表示的是从n个物品中选出m个物品的方案数。举个例子&#xff1a;从(1,2,3)三个物品中选择两个物品可以有(1,2)&#xff0c;(1,3)&#xff0c;(2,3) 这三种…

MySQl_1

一.相关概念 数据库&#xff1a;存放数据的仓库 数据库管理系统&#xff1a;操作和管理数据库的大型软件&#xff0c;如mysql SQL&#xff1a;一种操作 关系型数据库管理系统的语言&#xff0c;定义了一套操作关系型数据库管理系统的统一标准。 关系型数据库&#xff1a;有多…

客户案例 | 迎接智能化浪潮,传统水厂数字化势在必行

关键发现 客户痛点&#xff1a;传统水厂业务离散&#xff0c;无法实现数据实时同步&#xff0c;为收集和分析处理数据并辅助决策带来障碍。需要智能化管理系统帮助水厂提升管理效率&#xff0c;优化管理流程&#xff0c;实现数字化、智能化的目标。 解决方案&#xff1a;天津腾…

PyTorch深度学习实战 | 基于ResNet的人脸关键点检测

人脸关键点检测指的是用于标定人脸五官和轮廓位置的一系列特征点的检测&#xff0c;是对于人脸形状的稀疏表示。关键点的精确定位可以为后续应用提供十分丰富的信息。因此&#xff0c;人脸关键点检测是人脸分析领域的基础技术之一。许多应用场景(如人脸识别、人脸三维重塑、表情…

Mariadb10.5基于同服务器多实例主从配置

本次部署环境&#xff1a;Centos8stream 本次部署mariadb版本&#xff1a; mariadb:10.5 本次部署方式&#xff1a;rpm包直接安装&#xff0c;并通过systemd直接托管 可以参考 /usr/lib/systemd/system/mariadb.service 该文件 # Multi instance version of mariadb. For i…