Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)
概念
事务定义
事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。
事务特点
- 原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做
- 一致性:数据不会因为事务的执行而遭到破坏
- 隔离性:一个事务的执行,不受其他事务的干扰,即并发执行的事务之间互不干扰
- 持久性:一个事务一旦提交,它对数据库的改变就是永久的。
事务实现机制
Spring为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。
- 编程式事务管理: 编程式事务管理使用TransactionTemplate或者直接使用底层的 PlatformTransactionManager。对于编程式事务管理,spring 推荐使用 TransactionTemplate。
- 声明式事务管理: 建立在 AOP 之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
- 声明式事务管理不需要入侵代码,更快捷而且简单,推荐使用。
声明式事务有两种方式:
- 一种是在配置文件(xml)中做相关的事务规则声明(因为很少用本文不讲解)
- 另一种是基于**@Transactional**注解的方式。注释配置是目前流行的使用方式,推荐使用。
在应用系统调用声明了 @Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据 @Transactional 的属性配置信息,这个代理对象决定该声明 @Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑,最后根据执行情况是否出现异常,利用抽象事务管理器 AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
Spring AOP 代理有 CglibAopProxy 和 JdkDynamicAopProxy 两种,以 CglibAopProxy 为例,对于 CglibAopProxy,需要调用其内部类的 DynamicAdvisedInterceptor 的 intercept 方法。对于 JdkDynamicAopProxy,需要调用其 invoke 方法。
开启事务
注解 @Transactional 的使用
注解 @Transactional 常用配置
参 数 名 称
功 能 描 述
readOnly
用于设置当前事务是否为只读事务,设置为 true 表示只读,false 则表示可读写,默认值为 false。例如:@Transactional(readOnly=true)
rollbackFor
用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class);指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
transactionManager / value
多个事务管理器托管在 Spring 容器中时,指定事务管理器的 bean 名称
rollbackForClassName
用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称 @Transactional(rollbackForClassName=”RuntimeException”) 指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
noRollbackFor
用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName
用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”) 指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”, ”Exception”})
propagation
用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
isolation
用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout
该属性用于设置事务的超时秒数,默认值为 - 1 表示永不超时
事物超时设置:@Transactional(timeout=30) ,设置为 30 秒
Propagation 的属性(事务的传播行为)
例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
Propagation 属性
含义
REQUIRED
默认值 在有 transaction 状态下执行;如当前没有 transaction,则创建新的 transaction;
SUPPORTS
如当前有 transaction,则在 transaction 状态下执行;如果当前没有 transaction,在无 transaction 状态下执行;
MANDATORY
必须在有 transaction 状态下执行,如果当前没有 transaction,则抛出异常 IllegalTransactionStateException;
REQUIRES_NEW
创建新的 transaction 并执行;如果当前已有 transaction,则将当前 transaction 挂起;
NOT_SUPPORTED
在无 transaction 状态下执行;如果当前已有 transaction,则将当前 transaction 挂起;
NEVER
在无 transaction 状态下执行;如果当前已有 transaction,则抛出异常 IllegalTransactionStateException。
事务 5 种隔离级别
例如:@Transactional(isolation = Isolation.READ_COMMITTED)
隔离级别
含义
DEFAULT
这是一个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别另外四个与 JDBC 的隔离级别相对应;
READ_UNCOMMITTED
最低的隔离级别。事实上我们不应该称其为隔离级别,因为在事务完成前,其他事务可以看到该事务所修改的数据。而在其他事务提交前,该事务也可以看到其他事务所做的修改。可能导致脏,幻,不可重复读
READ_COMMITTED
大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。遗憾的是,在该事务提交后,你就可以查看其他事务插入或更新的数据。这意味着在事务的不同点上,如果其他事务修改了数据,你就会看到不同的数据。可防止脏读,但幻读和不可重复读仍可以发生。
REPEATABLE_READ
比 ISOLATION_READ_COMMITTED 更严格,该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其他事务修改了所查询的数据。然而如果其他事务插入了新数据,你就可以查询到该新插入的数据。可防止脏读,不可重复读,但幻读仍可能发生。
SERIALIZABLE
完全服从 ACID 的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。代价最大、可靠性最高的隔离级别,所有的事务都是按顺序一个接一个地执行。避免所有不安全读取。
使用注意事项(防止事务失效)
-
在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
-
**@Transactional 注解应该只被应用在 public 修饰的方法上。**如果你在 protected、private 或者 package-visible 的方法上使用 该注解,它也不会报错(IDEA 会有提示), 但事务并没有生效。
-
被外部调用的公共方法 A 有两个进行了数据操作的子方法 B 和子方法 C 的事务注解说明:
-
被外部调用的公共方法 A 未声明事务 @Transactional,子方法 B 和 C 若是其他类的方法且各自声明事务,则事务由子方法 B 和 C 各自控制
-
被外部调用的公共方法 A 未声明事务 @Transactional,子方法 B 和 C 若是本类的方法,则无论子方法 B 和 C 是否声明事务,事务均不会生效
-
被外部调用的公共方法 A 声明事务 @Transactional,无论子方法 B 和 C 是不是本类的方法,无论子方法 B 和 C 是否声明事务,事务均由公共方法 A 控制
-
被外部调用的公共方法 A 声明事务 @Transactional,子方法运行异常,但运行异常被子方法自己
try-catch
处理了,则事务回滚是不会生效的!如果想要事务回滚生效,需要将子方法的事务控制交给调用的方法来处理:
- 方案 1:子方法中不用
try-catch
处理运行异常 - 方案 2:子方法的 catch 里面将运行异常抛出【throw new RuntimeException();】
- 方案 1:子方法中不用
-
-
默认情况下,Spring 会对 unchecked 异常进行事务回滚,也就是默认对 RuntimeException() 异常或是其子类进行事务回滚。
如果是 checked 异常则不回滚,例如空指针异常、算数异常等会被回滚;文件读写、网络问题 Spring 就没法回滚。
若想对所有异常(包括自定义异常)都起作用,注解上面需配置异常类型:@Transactional(rollbackFor = Exception.class
-
数据库要支持事务,如果是 mysql,要使用 innodb 引擎,myisam 不支持事务
-
事务 @Transactional 由 spring 控制时,它会在抛出异常的时候进行回滚。如果自己使用 try-catch 捕获处理了,是不生效的。如果想事务生效可以进行手动回滚或者在 catch 里面将异常抛出【throw new RuntimeException();】
-
方案一:手动抛出运行时异常(缺陷是不能在 catch 代码块自定义返回值)
try{.... }catch(Exception e){logger.error("",e);throw new RuntimeException(e);}
-
方案二:手动进行回滚【 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 】
try{...}catch(Exception e){log.error("fail",e);TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return false;}
-
-
@Transactional 可以放在 Controller 下面直接起作用,看到网上好多同学说要放到 @Component 下面或者 @Service 下面,经过试验,可以不用放在这两个下面也起作用。
-
@Transactional 引入包问题,它有两个包:
import javax.transaction.Transactional; // 和 import org.springframework.transaction.annotation.Transactional; // 推荐
这两个都可以用,对比了一下他们两个的方法和属性,发现后面的比前面的强大。建议使用后面的。
使用场景
自动回滚
直接抛出,不 try/catch
@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder() throws Exception { success(); //假如exception这个操作数据库的方法会抛出异常,方法success()对数据库的操作会回滚。 exception(); return ApiReturnUtil.success();
}
手动回滚
进行 try/catch,回滚并抛出
@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){ success(); try { exception(); } catch (Exception e) { e.printStackTrace(); // 手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return ApiReturnUtil.error();} return ApiReturnUtil.success();
}
回滚部分异常
使用【Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 】设置回滚点。
使用【TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);】回滚到 savePoint。
@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){ success(); //只回滚以下异常,Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();try { exception(); } catch (Exception e) { e.printStackTrace(); // 手工回滚事务TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);return ApiReturnUtil.error();} return ApiReturnUtil.success();
}
手动创建、提交、回滚事务
PlatformTransactionManager 这个接口中定义了三个方法 getTransaction 创建事务,commit 提交事务,rollback 回滚事务。它的实现类是 AbstractPlatformTransactionManager。
@Autowired
priDataSourceTransactionManager dataSourceTransactionManager;
@Autowired
TransactionDefinition transactionDefinition;// 手动创建事务
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);// 手动提交事务
dataSourceTransactionManager.commit(transactionStatus);// 手动回滚事务。(最好是放在catch 里面,防止程序异常而事务一直卡在哪里未提交)
dataSourceTransactionManager.rollback(transactionStatus);
PlatformTransactionManager 手动提交事务,设置隔离级别
@Autowired
private PlatformTransactionManager transactionManager;public void test() {DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);try {// 数据库操作 //提交事务transactionManager.commit(transactionStatus);} catch (Exception e) {log.error("xxxx", e);//回滚事务transactionManager.rollback(transactionStatus);}
}
事务失效不回滚的原因及解决方案
异常被捕获导致事务失效
在 spring boot 中,使用事务非常简单,直接在方法上面加入 @Transactional 就可以实现。
@GetMapping("delete")
@ResponseBody
@Transactional
public void delete(@RequestParam("id") int id) { try { //delete countrythis.repository.delete(id); if(id == 1){ throw Exception("测试事务");} //delete citythis.repository.deleteByCountryId(id);}catch (Exception e){logger.error("delete false:" + e.getMessage()); }
}
发现事务不回滚,即 this.repository.delete(id);成功把数据删除了。
原因:
默认 spring 事务只在发生未被捕获的 RuntimeException 时才回滚。
spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样 aop 代理才能捕获到方法的异常,才能进行回滚,默认情况下 aop 只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚。
换句话说在 service 的方法中不使用 try catch 或者在 catch 中最后加上 throw new RuntimeExcetpion() 抛出运行异常,这样程序异常时才能被 aop 捕获进而回滚。
解决方案:
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>4.3.2.RELEASE</version></dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.9</version>
</dependency><plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration><showWeaveInfo>true</showWeaveInfo><aspectLibraries><aspectLibrary><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId></aspectLibrary></aspectLibraries>
</configuration><executions>
<execution><goals><goal>compile</goal><goal>test-compile</goal></goals>
</execution>
</executions>
</plugin>
解决方案
方案 1、在类上(或者最外层的公共方法)加事务
@Service
@Slf4j
public class MyTransactional {// 最外层公共方法。自动回滚事务方式,insertOrder()方法报错后事务回滚,且线程中止,后续逻辑无法执行@Transactionalpublic void test1() {this.insertOrder();System.out.println("11111111111111111");}// 最外层公共方法。手动回滚事务方式,insertOrder()方法报错后事务回滚,可以继续执行后续逻辑@Transactionalpublic void test2() {try { insertOrder();} catch (Exception e) { log.error("faild to ...", e);// 手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();// 其他操作}// 其他操作}// 进行数据库操作的方法(private 或 public 均可)private void insertOrder() {//insert log info//insertOrder//updateAccount}
}
方案 2、使用 AspectJ 取代 Spring AOP 代理
上面的两个问题 @Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,可以使用 AspectJ 取代 Spring AOP 代理。
需要将下面的 AspectJ 信息添加到 xml 配置信息中。
AspectJ 的 xml 配置信息
<tx:annotation-driven mode="aspectj" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property />
</bean>
</bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf"><property />
</bean>
同时在 Maven 的 pom 文件中加入 spring-aspects 和 aspectjrt 的 dependency 以及 aspectj-maven-plugin。
AspectJ 的 pom 配置信息
-
方案 1:例如 service 层处理事务,那么 service 中的方法中不做异常捕获,或者在 catch 语句中最后增加
throw new RuntimeException();
语句,以便让 aop 捕获异常再去回滚,并且在 service 的上层要继续捕获这个异常。 -
方案 2:在 service 层方法的 catch 语句中进行手动回滚,这样上层就无需去处理异常。
@GetMapping("delete") @ResponseBody @Transactional public Object delete(@RequestParam("id") int id){ if (id < 1){return new MessageBean(101,"parameter wrong: id = " + id) ; } try { //delete countrythis.countryRepository.delete(id);//delete citythis.cityRepository.deleteByCountryId(id);return new MessageBean(200,"delete success");}catch (Exception e){logger.error("delete false:" + e.getMessage());// 手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return new MessageBean(101,"delete false");} }
自调用导致事务失效
问题描述及原因
在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,否则会造成自调用问题。
若同一类中的 没有 @Transactional 注解的方法 内部调用 有 @Transactional 注解的方法,有 @Transactional 注解的方法的事务被忽略,不会发生回滚。见 示例代码展示。
自调用问题示例:
@Service public class OrderService {private void insert() {insertOrder();}@Transactionalpublic void insertOrder() {//insert log info//insertOrder//updateAccount} }// insertOrder() 尽管有@Transactional 注解,但它被内部方法 insert()调用,事务被忽略,出现异常事务不会发生回滚,并且会报错类似于:org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope(翻译:没有Transaction无法回滚事务。自调用导致@Transactional 失效。)
自调用失效原因:
-
spring 里事务是用注解配置的,当一个方法没有接口,单单只是一个内部方法时,事务的注解是不起作用的,需要回滚时就会报错。
-
出现这个问题的根本原因是:
@Transactional 的实现原理是 AOP,AOP 的实现原理是动态代理,而自调用时并不存在代理对象的调用,也就不会产生基于 AOP 的事务回滚操作
-
虽然可以直接从容器中获取代理对象,但这样有侵入之嫌,不推荐。
org.springframework spring-aspects 4.3.2.RELEASE org.aspectj aspectjrt 1.8.9 org.codehaus.mojo aspectj-maven-plugin 1.9 true org.springframework spring-aspects compile test-compile
其他
事务提交方式
默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。
对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,这个我们不用担心,spring 会将底层连接的【自动提交特性】设置为 false 。也就是在使用 spring 进行事务管理的时候,spring 会将【是否自动提交】设置为 false,等价于 JDBC 中的 connection.setAutoCommit(false); ,在执行完之后在进行提交 connection.commit(); 。
事务回滚规则
指示 spring 事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring 事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring 只有在抛出的异常为运行时 unchecked 异常时才回滚该事务,也就是抛出的异常为 RuntimeException 的子类 (Errors 也会导致事务回滚),而抛出 checked 异常则不会导致事务回滚。
可以明确的配置在抛出那些异常时回滚事务,包括 checked 异常。也可以明确定义那些异常抛出时不回滚事务。
事务并发会产生的问题
术语
含义
脏读
A 事务读取到了 B 事务还未提交的数据,如果 B 未提交的事务回滚了,那么 A 事务读取的数据就是无效的,这就是数据脏读
不可重复读
在同一个事务中,多次读取同一数据返回的结果不一致,这是由于读取事务在进行操作的过程中,如果出现更新事务,它必须等待更新事务执行成功提交完成后才能继续读取数据,这就导致读取事务在前后读取的数据不一致的状况出现
幻读
A 事务读取了几行记录后,B 事务插入了新数据,并且提交了插入操作,在后续操作中 A 事务就会多出几行原本不存在的数据,就像 A 事务出现幻觉,这就是幻读
第一类丢失更新
在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了。
例如:
张三的工资为 5000,事务 A 中获取工资为 5000,事务 B 获取工资为 5000,汇入 100,并提交数据库,工资变为 5100;
与此同时,事务B正在读取张三的工资,读取到张三的工资为8000。随后,事务A发生异常,回滚了事务,张三的工资又回滚为5000。最后,事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
脏读
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
张三的工资为 5000,事务 A 中把他的工资改为 8000,但事务 A 尚未提交。
与此同时,事务B正在读取张三的工资,读取到张三的工资为8000。随后,事务A发生异常,回滚了事务,张三的工资又回滚为5000。最后,事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
不可重复读
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
在事务 A 中,读取到张三的工资为 5000,操作没有完成,事务还没提交。
与此同时,事务 B 把张三的工资改为 8000,并提交了事务。
随后,在事务 A 中,再次读取张三的工资,此时工资变为 8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
第二类丢失更新
不可重复读的特例。
有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。
例如:
在事务 A 中,读取到张三的存款为 5000,操作没有完成,事务还没提交。
与此同时,事务 B 存入 1000,把张三的存款改为 6000,并提交了事务。
随后,在事务 A 中,存储 500,把张三的存款改为 5500,并提交了事务,这样事务 A 的更新覆盖了事务 B 的更新。
幻读
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
目前工资为 5000 的员工有 10 人,事务 A 读取到所有的工资为 5000 的人数为 10 人。
此时,事务 B 插入一条工资也为 5000 的记录。
这时,事务 A 再次读取工资为 5000 的员工,记录为 11 人。此时产生了幻读。
不可重复读和幻读的区别
不可重复读的重点是修改,同样的条件,你读取过的数据,再次读取出来发现值不一样了
幻读的重点在于新增或者删除,同样的条件,第 1 次和第 2 次读出来的记录数不一样
相关文章:
Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)
概念 事务定义 事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。…...
[gcc]代码演示-O使用场景
使用场景: 开发阶段: 在开发阶段,通常使用 -O0(无优化)以获得最快的编译速度和最完整的调试信息。这有助于快速迭代和调试。对于性能测试,可以使用 -O1 或 -O2 以获得一些基本的优化,同时保持较…...
conan从sourceforge.net下载软件失败
从sourceforge.net下载软件,经常会没有开始下载就返回了。 原因是: 自动选择的镜像站不能打开。 在浏览器中,我们可以手动选择站点尝试,但是conan就不行了。 手动选择一个站点,能够有文件保存窗口弹出,之后…...
电脑msvcp140.dll是什么文件?怎么修复电脑msvcp140.dll缺失的问题?
电脑msvcp140.dll文件详解及缺失问题修复指南 在探索电脑的奥秘时,我们时常会遇到各种文件、错误代码和系统问题。今天,我将为大家深入解析一个常见的系统文件——msvcp140.dll,以及当这个文件缺失时应该如何进行修复。作为一名在软件开发领…...
基于STM32的热带鱼缸控制系统的设计
文章目录 一、热带鱼缸控制系统1.题目要求2.思路3.电路仿真3.1 未仿真3.2 开始仿真,显示屏显示水温、浑浊度、光照强度等值3.3 当水温低于阈值,开启加热并声光报警3.4 当浑浊度高于阈值,开启自动换水并声光报警3.5 当光照低于阈值,…...
unity学习7:unity的3D项目的基本操作: 坐标系
目录 学习参考 1 unity的坐标系 1.1 左手坐标系 1.2 左手坐标系和右手坐标系的区别 1.3 坐标系的原点(0,0,0) 2 坐标系下的具体xyz坐标 2.1 position这里的具体xyz坐标值 2.2 父坐标 2.3 世界坐标和相对坐标 2.3.1 世界坐标 2.3.2 相对坐标 2.4 父物体,…...
认识一下,轻量消息推送 Server-Sent Events
什么是 SSE(Server-Sent Events) Server-Sent Events(简称 SSE)是一种在浏览器中实现单向实时通信的技术。它允许服务器通过 HTTP 持久连接向客户端发送实时更新的数据流。这种通信模式非常适用于需要频繁向客户端推送数据的场景,例如股票行情更新、实时聊天通知、社交媒…...
Python爬虫入门指南:从零开始抓取数据
Python爬虫入门指南:从零开始抓取数据 引言 在大数据时代,数据是新的石油。而爬虫作为获取数据的重要手段,受到了越来越多的关注。Python作为一门强大的编程语言,其简洁易用的特性使得它成为爬虫开发的首选语言。本篇文章将带你…...
c++ vector 使用find查找指定元素方法
在 C 中,std::vector 是一个动态数组,用于存储同类型元素的序列。如果你想在 std::vector 中查找指定元素,可以使用 std::find 算法。std::find 是定义在 <algorithm> 头文件中的标准库函数。 以下是一个示例代码,展示了如…...
计算机组成原理——控制单元设计
组合逻辑设计...
特征点检测与匹配——MATLAB R2022b
特征点检测与匹配在计算机视觉中的作用至关重要,它为图像处理、物体识别、增强现实等领域提供了坚实的基础。 目录 Harris角点检测 SIFT(尺度不变特征变换) SURF(加速稳健特征) ORB(Oriented FAST and Rotated BRIEF) 总结 特征点检测与匹配是计算机视觉中的一项基…...
在 IntelliJ IDEA 中开发 GPT 自动补全插件
背景与目标 随着 AI 的发展,GitHub Copilot 等智能代码补全工具在开发者中获得了广泛的应用,极大地提高了编程效率。本篇文章将教你如何开发一个 IntelliJ IDEA 插件,使用 OpenAI 的 GPT API 来实现类似 Copilot 的代码自动补全功能。通过这…...
主键有多种设计
1. 自增ID id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID 优点: 简单直观自动生成递增有序,对索引友好 缺点: 可能暴露业务信息分布式系统下需要特殊处理合并数据时可能冲突 2. UUID/GUID id char(36) NOT NULL COMMENT 主键ID …...
SCT12A0,一款2.7V-14V Vin、30W全集成同步升压转换器
SCT12A0是一款高效率,全集成 13mΩ 高侧MOSFET和11mΩ低侧MOSFET的同步升压转换器,支持 2.7V 至 14V 输入电压范围,最高可达12A 开关电流。开关电流限可以通过外部电阻进行调节。 SCT12A0采用自适应恒定关断时间峰值电流控制以提供快速瞬态。…...
Python 数据结构揭秘:栈与队列
栈(Stack) 定义 栈是一种后进先出(Last In First Out, LIFO)的数据结构。它类似于一个容器,只能在一端进行插入和删除操作。栈有两个主要的操作:push(入栈)和 pop(出栈…...
3、蓝牙打印机按键 - GPIO输入控制
1、硬件 1.1、看原理图 初始高电平,按键按下导通处于低电平状态。 PB8号引脚。 1.2、看手册 a、看系统架构 GPIOB号端口有APB2总线控制 b、RCC使能 RCC->APB2ENR的第3位控制GPIOB使能。 c、GPIOB寄存器配置 浮空输入模式下,I/O的电平状态是不确定…...
LeetCode--复原IP地址(面试手撕算法高频题)
题目描述:有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 . 分隔。 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.…...
050_小驰私房菜_MTK Camera debug, data rate 、mipi_pixel_rate 确认
mipi_pixel_rate = data rate * 4 / 10 (4 是表示4lane,10表示raw数据是10bit) mipi_pixel_rate 信息,我们可以通过 sentest命令打印看到: 下面的信息我们可以看到,mipi_pixel_rate = 501.357739Mpps,mipi rate = 10000000,是对应的我们驱动文件里面配置写的mipi_pixel_r…...
TCP粘/拆包----自定义消息协议
今天是2024年12月31日,今年的最后一天,希望所有的努力在新的一年会有回报。❀ 无路可退,放弃很难,坚持很酷 TCP传输 是一种面向二进制的,流的传输。在传输过程中最大的问题是消息之间的边界不明确。而在服务端主要的…...
conda指定路径安装虚拟python环境
DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 需要更多数据资源和技术解决方案,知识星球: “DataBall - X 数据球(free)” -------------------------------------------------------------…...
FPGA、STM32、ESP32、RP2040等5大板卡,结合AI,更突出模拟+数字+控制+算法
板卡选择困难症了?如果你也想玩FPGA、STM32、ESP32、RP2040相关的板卡,不如看看以下几款板卡,如果正巧碰上能实现你想要做的项目呢~ 01 小脚丫FPGA STEP BaseBoard V4.0套件 STEP BaseBoard V4.0是第4代小脚丫FPGA扩展底板(点击了…...
Flume拦截器的实现
Flume conf文件编写 vim file_to_kafka.conf#定义组件 a1.sources r1 a1.channels c1#配置source a1.sources.r1.type TAILDIR a1.sources.r1.filegroups f1 a1.sources.r1.filegroups.f1 /Users/zhangjin/model/project/realtime-flink/applog/log/app.* # 设置断点续传…...
【数据仓库】hadoop web UI 增加账号密码认证
升级了hadoop版本到3.3.6,未配置任何鉴权,默认端口9870 8088开放到了公网,结果没几天就被挖矿攻击了。通过开放的端口提交了很多非法任务到yarn上,并成功在服务器执行了恶意脚本。这次是真实真切的感受了,网络环境的险恶,以前仅仅是别人的案例来提高自己的安全意识,这…...
《特征工程:自动化浪潮下的坚守与变革》
在机器学习的广阔天地中,特征工程一直占据着举足轻重的地位。它宛如一位幕后的工匠,精心雕琢着原始数据,将其转化为能够被机器学习模型高效利用的特征,从而推动模型性能迈向新的高度。然而,随着技术的飞速发展…...
【亚马逊云科技】基于Amazon EKS部署高可用的OceanBase的最佳实践
一、前言 随着企业业务的快速发展和数据量的不断增长,高性能、高可用的数据库解决方案成为了关键需求。OceanBase作为一款分布式关系型数据库,以其高扩展性、高可用性和高性能的特点,逐渐受到企业的广泛关注。然而,在复杂的分布式…...
新能源电动汽车动力电池技术
新能源电动汽车动力电池技术是新能源汽车发展的核心之一,以下是动力电池技术的一些关键方面: 技术进展 能量密度提升:近年来,动力电池的能量密度有了显著提升,从2010年的100Wh/kg提高到2024年的300Wh/kg。能量密度的…...
小程序组件 —— 30 组件 - 背景图片的使用
在编写小程序的样式文件时,可以使用 background-image 属性来设置元素的背景图像;但是这个属性在微信小程序中使用时存在坑; 注意事项:微信小程序中的 background-iamge 不支持本地路径!需要使用网络图片,…...
量子力学复习
黑体辐射 热辐射 绝对黑体: (辐射能力很强,完全的吸收体,理想的发射体) 辐射实验规律: 温度越高,能量越大,亮度越亮 温度越高,波长越短 光电效应 实验装置…...
n8n - AI自动化工作流
文章目录 一、关于 n8n关键能力n8n 是什么意思 二、快速上手 一、关于 n8n n8n是一个具有原生AI功能的工作流自动化平台,它为技术团队提供了代码的灵活性和无代码的速度。凭借400多种集成、原生人工智能功能和公平代码许可证,n8n可让您构建强大的自动化…...
1.1.7 master公式的使用
code 递归例子 – 返回最大数据 # 递归行为, 返回[L, R]的最大值 # 递归:base case; 遍历;返回值 from test1 import *def getMax(arr):return process(arr, 0, len(arr)-1)def process(arr, L, R):if (L R):return arr[L] #…...
Windows系统安装Docker Desktop
文章目录 注意事项安装步骤官网下载软件安装到其它盘符操作(如果就想安装到C盘可以跳过这个步骤, 直接执行文件)等待出现软件安装界面Windows系统的配置软件的一些必要设置(以下设置需要点击apply才能生效,如果点不了,那就是安装后,出现了错误…...
快速上手LangChain(四)LangChain Hub和LangSmith
文章目录 快速上手LangChain(四)LangChain Hub和LangSmith什么是LangChain HubLangChain Hub功能 LangSmith使用 快速上手LangChain(四)LangChain Hub和LangSmith 什么是LangChain Hub LangChain Hub官网地址:https:…...
jquery实现的网页版扫雷小游戏源码
源码介绍 这是一款基于jQuery实现的经典扫雷小游戏源码,玩家根据游戏规则进行游戏,末尾再在确定的地雷位置单击右键安插上小红旗即可赢得游戏!是一款非常经典的jQuery游戏代码。本源码改进了获胜之后的读数暂停功能。 效果预览 源码下载 j…...
C#运动控制系统:雷赛控制卡实用完整例子 C#雷赛开发快速入门 C#雷赛运动控制系统实战例子 C#快速开发雷赛控制卡
雷赛控制技术 DMC系列运动控制卡是一款新型的 PCI/PCIe 总线运动控制卡。可以控制多个步进电机或数字式伺服电机;适合于多轴点位运动、插补运动、轨迹规划、手轮控制、编码器位置检测、IO 控制、位置比较、位置锁存等功能的应用。 DMC3000 系列卡的运动控制函数库功…...
理解linux内核中的几种地址
1. 前言 《Linux内核完全注释》这本书提到了几种Linux内核中的几种地址,实地址,有虚拟地址,逻辑地址,线性地址,物理地址。除了物理地址以外,其他几种容易弄混淆。这里做一下笔记,讲一下我的理解…...
MySQL(二)MySQL DDL数据库定义语言
1. MySQL DDL数据库定义语言 1.1. MySQL定义语言 进入MySQL mysql -u root -p(回车后输入密码,即可进入mysq1)1.1.1. 数据库操作 (1)查看数据库 mysql>show databases;注:MySQL语句分隔符为“;” mysql库很重要它里面有…...
《Vue3实战教程》19:Vue3组件 v-model
如果您有疑问,请观看视频教程《Vue3实战教程》 组件 v-model 基本用法 v-model 可以在组件上使用以实现双向绑定。 从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏: vue <!-- Child.vue --> <script setup> co…...
spring boot通过文件配置yaml里面的属性
yaml文件 fsg: batch-approval:# 批量审批batch-approval:pool:core-size: 2max-size: 10queue-capacity: 100keep-alive: 60name-prefix: ApprovalThread-shutdown:await-termination: trueawait-termination-period: 60ConfigurationProperties配置 import lombok.Data; imp…...
解析 World Football Cup 问题及其 Python 实现
问题描述 本文讨论一道关于足球锦标赛排名规则的问题,来自 Berland 足球协会对世界足球规则的调整。题目要求对给定的比赛数据进行计算,并输出能进入淘汰赛阶段的球队列表。以下是规则详细描述。 题目规则 输入格式: 第一行包含一个整数 …...
DS复习提纲模版
数组的插入删除 int SeqList::list_insert(int i, int item) { //插入if (i < 1 || i > size 1 || size > maxsize) {return 0; // Invalid index or list is full}for (int j size-1; j > i-1; j--) { // Shift elements to the rightlist[j1] list[j];}li…...
算法解析-经典150(链表、二叉树)
文章目录 链表1.环形链表1.答案2.思路 2.两数相加1.答案2.思路 3.合并两个有序链表1.答案2.思路 4.反转链表 II1.答案2.思路 5.反转链表1.答案2.思路 6.K 个一组翻转链表1.答案2.思路 7.删除链表的倒数第 N 个结点1.答案2.思路 8.删除排序链表中的重复元素 II1.答案2.思路 9.旋…...
蓝桥杯-Python
1. 冒泡排序 算法步骤: 比较相邻元素,如果第一个大于第二个则交换从左往右遍历一遍,重复第一步,可以保证最大的元素在最后面重复上述操作,可以得到第二大、第三大、… n int(input()) a list(map(int, input()…...
语雀导入md文件图片丢失
经常被困扰是,从语雀导入md文件,即使知道把md文件和本地图片文件夹打包成zip进行导入,还是出现图片丢失 解决方式1: 把图片和md文件放到同个目录下,重新打包成zip文件,导入后有图片了 解决方式2…...
【Logstash02】企业级日志分析系统ELK之Logstash 输入 Input 插件
Logstash 使用 Logstash 命令 官方文档 https://www.elastic.co/guide/en/logstash/current/first-event.html #各种插件 https://www.elastic.co/guide/en/logstash/current/input-plugins.html https://www.elastic.co/guide/en/logstash/current/filter-plugins.html htt…...
HP 电脑开机黑屏 | 故障判断 | BIOS 恢复 | BIOS 升级
注:本文为 “HP 电脑开机黑屏 | 故障判断 | BIOS 恢复 | BIOS 升级” 相关文章合辑。 引文图片 csdn 转储异常,重传。 篇 1:Smart-Baby 回复中给出故障现象判断参考 篇 2、篇3 :HP 官方 BIOS 恢复、升级教程 开机黑屏,…...
Nginx代理本地exe服务http为https
Nginx代理本地exe服务http为https 下载NginxNginx命令exe服务http代理为https 下载Nginx 点击下载Nginx 下载好之后是一个压缩包,解压放到没有中文的路径下就可以了 Nginx命令 调出cmd窗口cd到安装路径 输入:nginx -v 查看版本 nginx -hÿ…...
enzymejest TDD与BDD开发实战
一、前端自动化测试需要测什么 1. 函数的执行逻辑,对于给定的输入,输出是否符合预期。 2. 用户行为的响应逻辑。 - 对于单元测试而言,测试粒度较细,需要测试内部状态的变更与相应函数是否成功被调用。 - 对于集成测试而言&a…...
Linux菜鸟级常用的基本指令和基础知识
前言:很多Linux初学者都会头疼于指令太多记不住,笔者刚学习Linux时也是如此,学习Linux指令时,学了后面的指令,前面的指令也会忘的差不多了,针对于以上这些情况,笔者今天来分享一篇Linux菜鸟级的常用指令的博…...
Spark创建多种数据格式的DataFrame
假如我们要通过RDD[Row]创建一个包含多个列的DataFrame,重点是列的数据类型可能会包含多个,这时候需要有一点技巧。 | uid | user_name | age | income | |:----|:----------|:----|:-------| | 1111 | nituchao | 21 | 123.0 | 这个DataFrame里包含…...
C语言:指针
1. 什么是指针? 在C语言中,指针是一个变量,用于存储另一个变量的内存地址。指针不是直接保存值,而是保存数据所在的内存位置。 语法: type *pointer_name; 例如: int *ptr; 在这个例子中,pt…...