Spring事务和事务的传播机制(JavaEE进阶系列7)

目录

前言:

1.为什么需要事务

2.Spring中事务的实现

2.1编程式事务

2.2声明式事务

2.3@Transactional的作用范围

2.4@Transactional参数说明

2.5@Transactional的注意事项

2.6@Transactional工作原理

3.事务隔离级别

3.1事务特性的回顾

3.2Spring中设置事务的隔离级别

3.3MySQL事务隔离级别

3.4Spring的事务隔离级别

4.Spring事务的传播机制

4.1事务传播机制是什么

4.2为什么需要事务传播

结束语:


前言:

1.为什么需要事务

对于事务我们之前也是有所了解的我们在来回顾一下有关于事务的定义将一组操作封装成一个执行单元(封装在一起),要么全部执行成功,要么全部执行失败。

就拿转账来说:

  • 第一步操作:A账户向B账户转账100元,A账户 - 100元。
  • 第二步操作:B账户接收100元,B账户+100元。

如果没有事务,第一步如果成功了第二步失败了,那么A账户的100元就相当于是平白无故的人间蒸发了,不符合现实。所有使用事务就可以解决这个问题了,让这一组操作要么一起成功,要么一起失败。

2.Spring中事务的实现

在Spring中事务的操作分为两类:

  • 编程式事务(手动写代码的事务)。
  • 声明式事务(利用注解自动开启和提交事务)。

接下来我们先来回顾一下在MySQL中是如何使用的。

事务在MySQL中有三个重要的操作:开启事务(start transaction)、提交事务(commit)、回滚事务(rollback)

2.1编程式事务

Spring手动操作事务和上面MySQL操作事务类似,他也是有是三个重要的操作步骤:

  • 开启事务(获取事务)。
  • 提交事务。
  • 回滚事务。

SpringBoot内置了两个对象,DataSourceTransactionManager用来获取事务(开启事务)、提交或回滚事务的,而TransactionDefinition是事务的属性,在获取事务的时候要将TransactionDefinition传递进去从而获得一个事务TransactionStatus,实现代码如下所示:

package com.example.demo.controller;import com.example.demo.service.UserService;
import org.apache.catalina.User;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
public class UserController2 {@Resourceprivate UserService userService;//JDBC事务管理器@Resourceprivate DataSourceTransactionManager dataSourceTransactionManager;//定义事务属性@Resourceprivate TransactionDefinition transactionDefinition;@RequestMapping("/save")public Object save(User user) {//开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);//插入数据库int result = userService.save(user);//提交事务dataSourceTransactionManager.commit(transactionStatus);//回滚事务dataSourceTransactionManager.rollback(transactionStatus);return result;}
}

上述的实心方式太过于繁琐,所以接下来我们就使用声明式事务。

2.2声明式事务

声明式事务的实现很简单,只需要在需要的方法上添加@Transactional注解就可以实现了,无需手动开启事务和提交事务,进入方法时开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务,具体代码实现如下所示:

model层代码:

package com.example.demo.model;import lombok.Data;import java.time.LocalDateTime;@Data
public class Userinfo {private int id;private String username;private String password;private String photo;private LocalDateTime createtime;private LocalDateTime updatetime;private int state;
}

dao层代码:

package com.example.demo.dao;import com.example.demo.model.Userinfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {@Insert("insert into userinfo(username, password) values(#{username}, #{password})")int add(Userinfo userinfo);
}

service层代码:

package com.example.demo.service;import com.example.demo.dao.UserMapper;
import com.example.demo.model.Userinfo;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
@Service
public class UserService {@Resourceprivate UserMapper userMapper;public int add(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);return result;}
}

controller层代码:

package com.example.demo.controller;import com.example.demo.model.Userinfo;
import com.example.demo.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/add")@Transactionalpublic int add() {//1.非空判断Userinfo userinfo = new Userinfo();userinfo.setUsername("二二");userinfo.setPassword("123");//2.调用service执行添加int result = userService.add(userinfo);System.out.println("result: " + result);int n = 10 / 0;//3.将结果给前端return result;}
}

结果展示:

当启动服务器的时候访问页面的时候会出现报错异常。

在控制台中可以看到以及将数据添加到数据库中的信息。

但是在访问数据库的时候会发现没有数据,说明触发异常之后数据已经被回滚了。

2.3@Transactional的作用范围

@Transactional可以用来修饰方法或类:

  • 修饰方法时:需要注意只能用到public方法上,否则不生效。(推荐此种方法)
  • 修饰类时:表明该注解对该类中所有的public方法都生效。

2.4@Transactional参数说明

参数作用
value当配置了多个事务管理器时,可以使用该属性指定选择那个事务管理器。
transactionManager当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器。
propagation事务的传播行为,默认值为Propagation.REQUIRED
isolation事务的隔离级别,默认值为Isolation.DEFAULT
timeout事务的隔离级别,默认值为-1,如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly指定事务是否为只读事务,默认值为false,为了忽略那些不需要事务的方法,比如读取事务可以设置read-only为true。
rollbackFor用于指定能够触发事务回滚的异类型,可以指定多个异常。
rollbackForClassName用于指定能够触发事务回滚的异类型,可以指定多个异常。
noRollbackFor抛出指定的异常类型,不会滚事务,也可以指定多个异常类型。
noRollbackForClassName抛出指定的异常类型,不会滚事务,也可以指定多个异常类型。

2.5@Transactional的注意事项

当程序发生异常,但被try-catch处理之后,就不会发生自动回滚事务了。

如下代码所示:

注意这里只是在上述代码的基础之上改动了controller层的代码。

结果展示:

浏览器不会显示异常。


控制台会输出添加的信息。

数据库会面会显示出添加之后的数据。

这里大家就好奇了,为什么明明是发生了异常,为什么事务不回滚了?

原因是因为在Spring中是使用代理来进行管理的,而当异常被捕获之后,外部的代理就没有办法感受到异常信息了,所以就会直接将数据添加到数据库中,不进行回滚事务了。

那么针对于上述的情况当然也会有解决方法,根据它的原因我们就可以找到解决问题的办法了,我们可以让代理感受到异常信息,这样事务就会发生回滚了。下面是被try-catch处理之后,不自动回滚事务的解决方案:

①将异常继续抛出去(代理对象就能感受到异常,也就能自动回滚事务了)

代码展示:

结果展示:

浏览器访问的时候仍然会报错。

控制台显示结果如下所示:

数据库再次查询数据的时候,发现三三这条数据没有被加载到数据库中,已经别回滚了。

②使用代码手动回滚事务。

代码展示:

结果展示:
这次在浏览器中展示的就不是一大堆的报错信息了。

接下来是控制台的信息展示,也是显示已经将数据添加到数据库中了。

在数据库中会发现数据不存在,就说明已经被回滚掉了。

注意:以上两种都可以用来解决被try-catch处理之后,不能自动回顾事务的问题,但是一般我们使用第二种解决方案多,也是推荐的一种写法。

2.6@Transactional工作原理

@Transactional是基于AOP实现的,AOP又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用JDK的动态代理,如果目标对象没有实现接口,会使用CGLIB动态代理。

@Transactional在开始执行业务之前,通过代理先开启事务,在执行之后再提交事务。如果中途遇到异常,则回滚事务。

3.事务隔离级别

3.1事务特性的回顾

事务有4大特性(ACID),原子性、一致性、持久性、隔离性。具体的概念如下所示:

  • 原子性:一个事务(transaction)中的所有操作,要么全部执行完成,要么全部不执行。不会结束在中间某个环节。事务在执行的过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就这个事务从来没有执行过一样。
  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏的。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精准度、串行性以及后续数据库可以自发性的完成预定的工作。
  • 持久性:事务处理结束之后,对数据的修改就是永久的,即便系统故障也不会丢失。
  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同的级别,包括读未提交(Readuncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

在上述的四大特性中只有隔离性(隔离级别)是可以设置的。

为什么要设置事务的隔离级别?

设置事务的隔离级别是用来保障多个并发事务执行可控,更符合操作者的预期。

3.2Spring中设置事务的隔离级别

Spring中事务隔离级别可以通过@Transactional中的isolation属性来进行设置,如下所示:

3.3MySQL事务隔离级别

MySQL的事务隔离级别有以下4种:

  • READ UNCOMMITTED:读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读
  • READ COMMITTED:读已提交,也叫提交读,该隔离级别的事务能读取到以提交事务的数据,因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读
  • REPEATABLE READ:可重复读是MySQL的默认事务隔离级别,他能确保同一事务多次查询的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入的时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但自己就是插不进去,这就叫幻读(Phantom Read)
  • SERIALIZABLE:序列化,事务的最高隔离级别,他会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率太低,所以真正使用的场景并不多。
事务隔离级别脏读不可重复读幻读
读未提交(READ UNCOMMITTED)
读已提交(READ COMMITED)×
可重复读(REPEATABLE READ)××
串行化(SERIALIZABLE)×××

脏读、幻读、不可重复读导致的原因如下所示: 

  • 脏读:一个事务读取到另一个事务修改的数据之后,后一个事务又进行了回滚操作,从而导致第一个事务读取的数据是错误的。
  • 不可重复读:一个事务两次查询得到的结果不同,因为在两次查询中间,有另一个事务把数据修改了。
  • 幻读:一个事务两次查询中得到的结果集不同,因为在两次查询中另一个事务又新增了一部分数据。

在数据库中我们可以通过以下SQL语句来查询到当前全局事务隔离级别和当前连接的事务隔离级别: 

那么在MySQL中到底有没有解决掉幻读的问题呢?

有但是又没彻底解决,因为 REPEATABLE READ 是通过 + MVCC来进行解决幻读问题的,但是REPEATABLE READ又有两种读,一种是当前读,一种是快照读,快照读的时候是从内存中读取的。所以快照读通过+MVCC是可以解决掉幻读问题的,而当前读是读取当前的数据,可能会发生变化,所以当前读+MVCC是解决不掉幻读问题的,除非加锁。

所以要想彻底解决幻读问题有两种解决办法:

  1. 串行化。
  2. MVCC+锁。

3.4Spring的事务隔离级别

而Spring中事务隔离级别包含以下5种:

  • Isolation.DEFAULT:以连接的数据的事务隔离级别为主。
  • Isolation.READ_UNCOMMITTED:读未提交,可以读到未提交的事务,存在脏读。
  • Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重复读。
  • Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读(MySQL默认级
  • 别)。
  • Isolation.SERIALIZABLE:可以解决所有的并发问题,但是性能太低。

从上述介绍中可以看出,相比于MySQL的事务隔离级别,Spring的事务隔离级别只是多一个Isolation.DEFAULT(以数据库的全局事务隔离级别为主)。

我们只需要在Spring事务中设置@Transactional里的属性isolation属性的隔离级别即可,如下代码所示:

4.Spring事务的传播机制

4.1事务传播机制是什么

Spring事务传播机制定义了多个包含了事务的方法,互相调用,事务是如何在这些方法间进行传递的。他其实就是规定了多个事务在互相调用时,事务的执行行为。

4.2为什么需要事务传播

事务的隔离级别是保证多个并发执行的可控性(稳定性的),而事务传播机制是保证一个事务在多个调用方法间的可控性(稳定性)。就像是疫情期间,会存在不同的隔离方式,酒店隔离、居家隔离...,这就是为了保证疫情的可控性。事务的隔离级别解决的是多个事务同时调用一个数据库的问题,如下所示:

而事务的传播机制解决的是一个事务在多个节点(方法)中传递的问题,如下所示:

4.3事务的七大传播机制

Spring事务的传播机制包含以下7点:

  • Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • Propagation.REQUIRES_NEW:表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开起自己的事务,且开启的事务相互独立,互不干扰。
  • Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,则把当前事务挂起。
  • Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果没有事务,则该取值等价于PROPAGATION_REQUIRED。

针对于Propagation.REQUIRED它是表示如果当前存在事务,则加入该事务,没有存在则不加入,以非事务的方式继续运行。接下来我们通过画图和代码来给大家进行具体演示一下。

代码展示:

Controller层代码展示:

package com.example.demo.controller;import com.example.demo.model.Userinfo;
import com.example.demo.service.UserService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/add")@Transactional(propagation = Propagation.REQUIRED)public int add() {//1.非空判断Userinfo userinfo = new Userinfo();userinfo.setUsername("思思");userinfo.setPassword("123456");//2.调用service执行添加int result = userService.add(userinfo);System.out.println("result: " + result);try {int n = 10 / 0;} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}//3.将结果给前端return result;}
}

Service层代码展示:

package com.example.demo.service;import com.example.demo.dao.UserMapper;
import com.example.demo.model.Userinfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
@Service
public class UserService {@Resourceprivate UserMapper userMapper;@Transactional(propagation = Propagation.REQUIRED)public int add(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);insert(userinfo);return result;}@Transactional(propagation = Propagation.REQUIRED)public int insert(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);int n = 10 / 0;return result;}
}

结果展示:

浏览器页面展示,会发现存在算数异常。

控制台会发现有插入的两条数据的记录。

在数据库中发现没有插入任何数据,说明在触发异常之后数据都被回滚了。

解析:当使用Propagation.REQUIRED时说明第一个事务已经开启了事务了,则后续的事务发现前面的事务开启之后就会加入到事务中来。如下图所示:

针对于Propagation.SUPPORTS它是如存在当前事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

代码展示:

controller层代码展示:

package com.example.demo.controller;import com.example.demo.model.Userinfo;
import com.example.demo.service.UserService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/add")@Transactional(propagation = Propagation.SUPPORTS)public int add() {//1.非空判断Userinfo userinfo = new Userinfo();userinfo.setUsername("思思");userinfo.setPassword("123456");//2.调用service执行添加int result = userService.add(userinfo);System.out.println("result: " + result);try {int n = 10 / 0;} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}//3.将结果给前端return result;}
}

service层代码展示:

package com.example.demo.service;import com.example.demo.dao.UserMapper;
import com.example.demo.model.Userinfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
@Service
public class UserService {@Resourceprivate UserMapper userMapper;@Transactional(propagation = Propagation.SUPPORTS)public int add(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);insert(userinfo);return result;}@Transactional(propagation = Propagation.SUPPORTS)public int insert(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);int n = 10 / 0;return result;}
}


结果展示:

浏览器依然会报错:


控制台中会显示插入数据。

在数据库中国会发现插入了两条数据,说明他是以非事务的方式运行的。

画图解析:


针对于 Propagation.NESTED 它表示当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则该取值等于PROPAGATION_REQUIRED。

代码展示:

Controller层代码展示:

package com.example.demo.controller;import com.example.demo.model.Userinfo;
import com.example.demo.service.UserService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
@RequestMapping("/user")
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/add")@Transactional(propagation = Propagation.NESTED)public int add() {//1.非空判断Userinfo userinfo = new Userinfo();userinfo.setUsername("五五");userinfo.setPassword("123456");//2.调用service执行添加int result = userService.add(userinfo);System.out.println("result: " + result);userService.insert(userinfo);
//        try {
//            int n = 10 / 0;
//        } catch (Exception e) {
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//        }//3.将结果给前端return result;}
}


service层代码展示:

package com.example.demo.service;import com.example.demo.dao.UserMapper;
import com.example.demo.model.Userinfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;import javax.annotation.Resource;
@Service
public class UserService {@Resourceprivate UserMapper userMapper;@Transactional(propagation = Propagation.REQUIRED)public int add(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);return result;}@Transactional(propagation = Propagation.REQUIRED)public int insert(Userinfo userinfo) {int result = userMapper.add(userinfo);System.out.println("add result -> " + result);try {int n = 10 / 0;} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return result;}
}

结果展示:

对于浏览器端仍然出现报错现象,但是不是算数异常错误了。

对于控制台依然会显示插入两条数据。

对于数据库而言它不会插入一条数据,所有的数据都会被回滚掉。

画图解释:

结束语:

好了这节小编就给大分享到这里啦,希望这节对大家有关于Spring事务和事务的传播机制的基础知识的了解有一定帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

区,段,碎片区与表空间结构

区,段,碎片区与表空间结构 结构图 另外在数据库中,还存在着区(Extent),段(Segment)和表空间(Tablespace)的概念。行,页,区&#xff…

03_51单片机点亮LED灯

51单片机是一种非常常见的单片机型号,广泛应用于各种嵌入式系统和电子设备中。LED灯是一种常见的输出设备,用于显示信息或指示状态。下面是关于51单片机控制LED灯的介绍: 1. 连接LED灯:将LED的正极连接到51单片机的一个I/O引脚&a…

【LeetCode】33. 搜索旋转排序数组

1 问题 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nums…

【Linux】Ubuntu美化bash【教程】

【Linux】Ubuntu美化bash【教程】 文章目录 【Linux】Ubuntu美化bash【教程】1. 查看当前环境中是否有bash2. 安装Synth-Shell3. 配置Synth-Shell4. 取消greeterReference 1. 查看当前环境中是否有bash 查看当前使用的bash echo $SHELL如下所示 sjhsjhR9000X:~$ echo $SHELL…

在 Android 上恢复已删除音乐的 5 种简单方法

人们经常将重要的音乐文件保存在智能手机上&#xff0c;以方便随时随地收听自己喜欢的曲目。但是&#xff0c;如果这些珍贵的音乐文件因软件故障或硬件故障而被意外删除或丢失怎么办&#xff1f;这将是许多音乐爱好者的噩梦&#xff01; 如果您也是这些人中的一员&#xff0c;…

Linux shell编程学习笔记13:文件测试运算

Linux Shell 脚本编程和其他编程语言一样&#xff0c;支持算数、关系、布尔、逻辑、字符串、文件测试等多种运算。前面几节我们依次研究了 Linux shell编程 中的 字符串运算、算术运算、关系运算、布尔运算 和 逻辑运算&#xff0c;今天我们来研究 Linux shell编程中的文件测…

【设计模式-1】UML和设计原则

说明&#xff1a;设计模式&#xff08;Design Pattern&#xff09;对于软件开发&#xff0c;简单来说&#xff0c;就是软件开发的套路&#xff0c;固定模板。在学习设计模式之前&#xff0c;需要首先学习UML&#xff08;Unified Modeling Language&#xff0c;统一建模语言&…

(Python) Python中三种时间格式的转换方法

1. 时间元组 1.1. 时间元组和时间戳的互相转化 import time,datetime # 获取当前时间的时间元组 t time.localtime() print(t) # 时间元组转时间戳 timestamp time.mktime(t) print(timestamp) # time.struct_time(tm_year2019, tm_mon10, tm_mday23, tm_hour23, tm_min15,…

漏洞复现--安恒明御安全网关文件上传

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

web 安全总结

1、web安全总结 1.1 web安全简介 1.1.1 http协议 http 协议是超文本传输协议-明文传输 https 协议是http协议的基础上进行升级&#xff0c;是数据在传输过程中进行加密 1.1.2 http请求 http请求分为&#xff1a;请求方法、请求头、请求体 GET、PUT、POST、OPTIONS、move、…

【Unity HDRP渲染管线下的WorleyUtilities文件,“Hash”函数】

Unity HDRP内置文件WorleyUtilities WorleyUtilities文件路径如下:文件代码如下然后转译到ShaderLab中:存档:WorleyUtilities文件路径如下: D:…\Library\PackageCache\com.unity.render-pipelines.high-definition@14.0.8\Runtime\Lighting\VolumetricClouds\WorleyUtili…

Ubuntu - 查看 IP 地址

要查看 Ubuntu 操作系统中的 IP 地址&#xff0c;可以使用 ip 命令或者 ifconfig 命令。以下是使用这两个命令的示例&#xff1a; 使用 ip 命令&#xff1a; 打开终端。 输入以下命令&#xff1a; ip a 这将显示网络接口信息&#xff0c;包括 IP 地址。通常&#xff0c;IP…

安科瑞预付费电能管理系统在学生公寓的应用与分析

安科瑞 崔丽洁 摘要&#xff1a;论文设计了适用于学生公寓的自助式预付费控电控水管理系统&#xff0c;采用多种智能功能&#xff0c;可以监测和显示漏电现象&#xff0c;通过短路、跳线、零线接地等方式防范和记录用户的偷电行为&#xff0c;通过报警和拉闸防止事故的发生。预…

嵌入式实时操作系统的设计与开发(调度策略学习)

将调度分为两层&#xff0c;上层为策略&#xff0c;下层为机制&#xff0c;并且采用策略与机制分离的设计原则&#xff0c;可以方便灵活地扩展调度策略&#xff0c;而不改变底层的调度机制。 调度策略就是如何确定线程的CPU、优先级prio等参数&#xff0c;线程是按照FIFO&…

掌控安全Update.jsp SQL注入

0x01 漏洞介绍 亿赛通电子文档安全管理系统是国内最早基于文件过滤驱动技术的文档加解密产品之一&#xff0c;保护范围涵盖终端电脑&#xff08;Windows、Mac、Linux系统平台&#xff09;、智能终端&#xff08;Android、IOS&#xff09;及各类应用系统&#xff08;OA、知识管理…

metaRTC7集成lvgl ui demo编译指南

概要 开源轻量级嵌入式图形库lvgl:Light and Versatile Graphics Library&#xff0c;最低只需8kb内存&#xff0c;可为任何 MCU、MPU 和显示类型创建漂亮的 UI。 metaRTC新增lvgl demo&#xff0c;可在linux下编译运行。 源码下载 https://github.com/metartc/metaRTC/rel…

小程序首页搭建

小程序首页搭建 1. Flex布局是什么&#xff1f;2. 容器的属性2.1 flex-direction属性2.2 flex-wrap属性2.3 flex-flow属性2.4 justify-content属性2.5 align-items属性2.6 align-content属性 二.首页布局搭建二.1moke模拟数据实现轮播图4.信息搭建 Flex弹性布局 1. Flex布局是…

Docker基础操作命令演示

Docker中的常见命令&#xff0c;可以参考官方文档&#xff1a;https://docs.docker.com/engine/reference/commandline/cli/ 1、常见命令介绍 其中&#xff0c;比较常见的命令有&#xff1a; 命令说明文档地址docker pull拉取镜像docker pulldocker push推送镜像到DockerReg…

【塔防】1,游戏架构

游戏架构 一&#xff0c;StoneDefence核心架构分析1&#xff0c;安装2&#xff0c;核心框架2.1创建核心核心环境2.1.1游戏中的核心元素&#xff08;GameCore&#xff09;ApawnGameInstanceGameStatePlayerStatePlayerControllerGameUserSettings 2.1.2大厅中的核心元素&#xf…

水库大坝安全监测是什么和主要作用?

水库大坝安全监测是指通过仪器观测和巡视检查对水利水电工程主体结构、地基基础、两岸边坡、相关设施以及周围环境所作的测量及观察。大坝安全监测是作为水库大坝安全管理的重要组成部分&#xff0c;是掌握水库大坝安全性态的重要手段&#xff0c;是科学调度、安全运行的前提。…