Spring源码-从源码层面讲解传播特性

传播特性:service:REQUIRED,dao:REQUIRED

两个都是required使用的是同一个事务,正常情况,在service提交commit

    <tx:advice id="myAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="checkout" propagation="REQUIRED" /><tx:method name="updateStock" propagation="REQUIRED" /></tx:attributes></tx:advice>

service:

    public void checkout(String username,int id){try {bookDao.updateStock(id);} catch (Exception e) {e.printStackTrace();}}

dao:

    public void updateStock(int id){String sql = "update book_stock set stock=stock-1 where id=?";jdbcTemplate.update(sql,id);for (int i = 1 ;i>=0 ;i--)System.out.println(10/i);}

dao层抛出异常导致
在这里插入图片描述
service层事务:外层开始没有事务所以这里是true
在这里插入图片描述

dao内层事务因为传播特性是required所以复用的是外层service事务
在这里插入图片描述
在这里插入图片描述
newSynchronization变为false
在这里插入图片描述

old是外层service,this是当前dao的
在这里插入图片描述
这里执行的sql不会实际生效因为没有commit,下面for会有异常 看看后续怎么处理异常再事务
在这里插入图片描述
在这里插入图片描述
completeTransactionAfterThrowing异常回滚
在这里插入图片描述

在这里插入图片描述
先处理回滚的规则,就是事务注解里的rollbackFor,rollbackForClassName,noRollbackFor,noRollbackForClassName属性如果没有设置就会调用父类的rollbackOn
在这里插入图片描述
super.rollbackOn(ex);
在这里插入图片描述
开始completeTransactionAfterThrowing的txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
在这里插入图片描述
在这里插入图片描述
把外层事务信息恢复回去
在这里插入图片描述
开始打印异常信息
在这里插入图片描述
在service层捕获了异常没有抛 所以外层事务不回滚
在这里插入图片描述
在这里完成回滚
在这里插入图片描述
UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only异常在这里抛出
在这里插入图片描述
数据库数据不会被修改

service:REQUIRED,dao:NESTED

    <tx:advice id="myAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="checkout" propagation="REQUIRED" /><tx:method name="updateStock" propagation="NESTED" /></tx:attributes></tx:advice>

PROPAGATION_NESTED为事务设置一个回退点
在这里插入图片描述
在这里插入图片描述

设置mysql连接的保存点
在这里插入图片描述
保存点设置完成
在这里插入图片描述

createAndHoldSavepoint:140, AbstractTransactionStatus (org.springframework.transaction.support)
handleExistingTransaction:490, AbstractPlatformTransactionManager (org.springframework.transaction.support)
getTransaction:356, AbstractPlatformTransactionManager (org.springframework.transaction.support)
createTransactionIfNecessary:588, TransactionAspectSupport (org.springframework.transaction.interceptor)
invokeWithinTransaction:367, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
updateStock:-1, BookDao$$EnhancerBySpringCGLIB$$421d7dae (com.mashibing.tx.xml.dao)
checkout:25, BookService (com.mashibing.tx.xml.service)
invoke:-1, BookService$$FastClassBySpringCGLIB$$66a1e40d (com.mashibing.tx.xml.service)
invoke:218, MethodProxy (org.springframework.cglib.proxy)
invokeJoinpoint:802, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceed:172, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceedWithInvocation:-1, 1079125839 (org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$47)
invokeWithinTransaction:374, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
checkout:-1, BookService$$EnhancerBySpringCGLIB$$d6fab840 (com.mashibing.tx.xml.service)
main:17, TxTest (com.mashibing.tx.xml)

代码执行到这里没有新建连接,用的是外层方法事务和连接。
在这里插入图片描述
在mysql中保存点的使用:
stock=100 设置保存点p1 后面会回滚到P1 就能实现一个事务中部分成功部分失败。stock最后变为97,说明前三个修改语句生效,后三个失败,保存点的作用就是保存保存点之前的sql生效。后边的会回滚不会实际生效
在这里插入图片描述
执行dao的内层方法抛异常,此时事务有保存点在这里执行回滚保存点的操作,并且把rollbackOnly变为false,来进行重置保存点。
在这里插入图片描述
外层service捕获异常,继续后续执行
在这里插入图片描述
直接执行下面的commit,上面的两个if进不去
在这里插入图片描述
此时执行的是service的外层事务,没有保存点直接执行docommit,外层方法正常提交结束。
在这里插入图片描述

在这里插入图片描述
service:REQUIRED,dao:REQUIRED_NEW
BookDao的内层方式这里能获取到threadlocal里的连接。
在这里插入图片描述

doGetTransaction:275, DataSourceTransactionManager (org.springframework.jdbc.datasource)
getTransaction:349, AbstractPlatformTransactionManager (org.springframework.transaction.support)
createTransactionIfNecessary:588, TransactionAspectSupport (org.springframework.transaction.interceptor)
invokeWithinTransaction:367, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
updateStock:-1, BookDao$$EnhancerBySpringCGLIB$$46f7c792 (com.mashibing.tx.xml.dao)
checkout:25, BookService (com.mashibing.tx.xml.service)
invoke:-1, BookService$$FastClassBySpringCGLIB$$66a1e40d (com.mashibing.tx.xml.service)
invoke:218, MethodProxy (org.springframework.cglib.proxy)
invokeJoinpoint:802, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceed:172, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceedWithInvocation:-1, 1988939205 (org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$47)
invokeWithinTransaction:374, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
checkout:-1, BookService$$EnhancerBySpringCGLIB$$dbd50224 (com.mashibing.tx.xml.service)
main:17, TxTest (com.mashibing.tx.xml)

存在外部事务
在这里插入图片描述
当前dao是PROPAGATION_REQUIRES_NEW,先挂起外层事务
在这里插入图片描述
SuspendedResourcesHolder 挂起

/*** 有些传播机制需要挂起当前的事务,比如NOT_SUPPORTED,REQUIRES_NEW首先会清除所有线程相关的同步状态,如果当前事务存在的话,就进行一些属性的清除,比如清空连接持有器,清空线程私有变量的同步状态,* 最后把当前事务清除的属性保存到一个SuspendedResourcesHolder里,以便于恢复的时候设置会去*/@Nullableprotected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {// 判断当前的线程变量中有没有激活的事物,有需要清空线程变量if (TransactionSynchronizationManager.isSynchronizationActive()) {List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();try {Object suspendedResources = null;if (transaction != null) {//挂起的资源,连接持有器suspendedResources = doSuspend(transaction);}// 获取当前事务名称String name = TransactionSynchronizationManager.getCurrentTransactionName();// 清空线程变量TransactionSynchronizationManager.setCurrentTransactionName(null);// 获取出只读事务的名称boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();// 清空线程变量TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);// 获取已存在事务的隔离级别Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();// 清空隔离级别TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);// 判断当前事务激活状态boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();// 清空标记TransactionSynchronizationManager.setActualTransactionActive(false);// 把上诉从线程变量中获取出来的存在事务属性封装为挂起的事务属性返回出去return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);}catch (RuntimeException | Error ex) {// doSuspend failed - original transaction is still active...doResumeSynchronization(suspendedSynchronizations);throw ex;}}else if (transaction != null) {// Transaction active but no synchronization active.Object suspendedResources = doSuspend(transaction);return new SuspendedResourcesHolder(suspendedResources);}else {// Neither transaction nor synchronization active.return null;}}

doSuspend
清空连接持有器

	/*** 实际挂起资源的方法* @param transaction the transaction object returned by {@code doGetTransaction}* @return*/@Overrideprotected Object doSuspend(Object transaction) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;// 清空连接持有器txObject.setConnectionHolder(null);// 解绑线程私有的资源return TransactionSynchronizationManager.unbindResource(obtainDataSource());}

实际处理挂起事务 清除threadlocal的副本
在这里插入图片描述
被挂起的历史事务相关属性信息
在这里插入图片描述
doBegin(transaction, definition);// 开启事务和连接
开启连接和事务
service层的事务和dao层的不关联,各自有各自的事务和数据库连接,内层回滚不影响外层的了

 通过数据源获取一个数据库连接对象 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">// 通过数据源获取一个数据库连接对象 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">Connection newCon = obtainDataSource().getConnection();//从DruidDataSource获取连接if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}// 把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去txObject.setConnectionHolder(new ConnectionHolder(newCon), true);。。。。。。// 关闭自动提交 如果不i关闭每次sql执行就自动提交了if (con.getAutoCommit()) {//设置需要恢复自动提交txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}// 关闭自动提交con.setAutoCommit(false);}。。。。。。// Bind the connection holder to the thread.// 绑定我们的数据源和连接到我们的同步管理器上,把数据源作为key,数据库连接作为value 设置到线程变量中if (txObject.isNewConnectionHolder()) {// 将当前获取到的连接绑定到当前线程 数据源和连接持久器进行绑定TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}

后续执行dao层抛出异常

completeTransactionAfterThrowing:668, TransactionAspectSupport (org.springframework.transaction.interceptor)
invokeWithinTransaction:379, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
updateStock:-1, BookDao$$EnhancerBySpringCGLIB$$46f7c792 (com.mashibing.tx.xml.dao)
checkout:25, BookService (com.mashibing.tx.xml.service)
invoke:-1, BookService$$FastClassBySpringCGLIB$$66a1e40d (com.mashibing.tx.xml.service)
invoke:218, MethodProxy (org.springframework.cglib.proxy)
invokeJoinpoint:802, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceed:172, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceedWithInvocation:-1, 1988939205 (org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$47)
invokeWithinTransaction:374, TransactionAspectSupport (org.springframework.transaction.interceptor)
invoke:125, TransactionInterceptor (org.springframework.transaction.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
invoke:100, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:199, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:780, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
intercept:721, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
checkout:-1, BookService$$EnhancerBySpringCGLIB$$dbd50224 (com.mashibing.tx.xml.service)
main:17, TxTest (com.mashibing.tx.xml)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

	/*** 真正回滚的处理方法,也就是获取JDBC连接,然后回滚* @param status the status representation of the transaction*/@Overrideprotected void doRollback(DefaultTransactionStatus status) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();Connection con = txObject.getConnectionHolder().getConnection();if (status.isDebug()) {logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");}try {// jdbc的回滚con.rollback();}catch (SQLException ex) {throw new TransactionSystemException("Could not roll back JDBC transaction", ex);}}

cleanupAfterCompletion

	/*** 回滚后的处理工作,如果是新的事务同步状态的话,要把线程的同步状态清除了,* 如果是新事务的话,进行数据清除,线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,释放连接等。* 如果有挂起的事务,还要把这个事务给恢复,其实就是把属性设置回去** Clean up after completion, clearing synchronization if necessary,* and invoking doCleanupAfterCompletion.* @param status object representing the transaction* @see #doCleanupAfterCompletion*/private void cleanupAfterCompletion(DefaultTransactionStatus status) {// 设置完成状态status.setCompleted();if (status.isNewSynchronization()) {// 线程同步状态清除TransactionSynchronizationManager.clear();}// 如果是新事务的话,进行数据清除,线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,释放连接等if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}// 有挂起的事务要恢复if (status.getSuspendedResources() != null) {if (status.isDebug()) {logger.debug("Resuming suspended transaction after completion of inner transaction");}Object transaction = (status.hasTransaction() ? status.getTransaction() : null);// 结束之前事务的挂起状态resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());}}

resume恢复外层事务到本地线程,如果service方法有多个事务dao执行完一个dao需要将service的事务恢复到线程

	/*** 如果前面有事务被挂起,现在就要回复,其实就是把一些属性设置回去** Resume the given transaction. Delegates to the {@code doResume}* template method first, then resuming transaction synchronization.* @param transaction the current transaction object* @param resourcesHolder the object that holds suspended resources,* as returned by {@code suspend} (or {@code null} to just* resume synchronizations, if any)* @see #doResume* @see #suspend*/protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)throws TransactionException {// 设置属性和状态if (resourcesHolder != null) {Object suspendedResources = resourcesHolder.suspendedResources;if (suspendedResources != null) {doResume(transaction, suspendedResources);}List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;//如果有挂起同步器的话要设置线程私有变量的值为挂起事务的相关属性if (suspendedSynchronizations != null) {TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);doResumeSynchronization(suspendedSynchronizations);}}}

service中对异常catch后续就不会处理异常 直接commit

    public void checkout(String username,int id){try {bookDao.updateStock(id);} catch (Exception e) {e.printStackTrace();}}

在这里插入图片描述
1.如果service不catch异常会继续向外抛,最终会导致service层也会回滚 ,如此一来,service和dao一共回滚两次;即dao抛出没捕获,dao回滚,此时service捕获了就不回滚,没捕获也会回滚;
2.如果外层有异常抛出,内层正常执行,外层不会导致内层回滚,内层会影响外层,外层不会影响内层;即内外两层是不同事务,内层提交过了,外层有异常没捕获,外层事务回滚,此时内层事务不受影响

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

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

相关文章

【C++笔试强训】如何成为算法糕手Day2

学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 第一题&#xff1a;牛牛的快递 第二题&#xff1a;最小花费爬楼梯 第三题&#xff1a;数组中两个字符串的最小距离 补充0x3f3f3f3f 第一题…

CSS样式的4种引入方法

1.行内样式 1.只能影响标签内的样式 2.行内样式可以应用在<body>标记内的所有子标记包括<body>标记在内&#xff0c;但是不能用在<head><title><meta>中 3&#xff0c;行内样式的标记优先级最高 语法&#xff1a;直接再标记内写style属性 &…

centos7 配置 docker 国内镜像源

1.修改配置文件/etc/docker/daemon.json sudo vim /etc/docker/daemon.json2.增加或修改以下配置内容 {"registry-mirrors": ["https://dockerproxy.com","https://hub-mirror.c.163.com","https://mirror.baidubce.com","http…

力扣P1706全排列问题 很好的引入暴力 递归 回溯 dfs

代码思路是受一个洛谷题解里面大佬的启发。应该算是一个dfs和回溯的入门题目&#xff0c;很好的入门题目了下面我会先给我原题解思路我想可以很快了解这个思路。下面是我自己根据力扣大佬写的。 我会进行详细讲解并配上图辅助理解大家请往下看 #include<iostream> #inc…

【SkySat卫星】

SkySat卫星 SkySat卫星是由美国商业遥感公司行星&#xff08;Planet Labs&#xff09;发射和运营的一系列高分辨率对地观测卫星。以下是对SkySat卫星的详细介绍&#xff1a; 一、基本信息 国籍&#xff1a;美国研发机构&#xff1a;最初由天盒成像公司&#xff08;Skybox I…

Linux驱动开发初识

Linux驱动开发初识 文章目录 Linux驱动开发初识一、驱动的概念1.1 什么是驱动&#xff1a;1.2 驱动的分类&#xff1a; 二、设备的概念2.1 主设备号&次设备号&#xff1a;2.2 设备号的作用&#xff1a; 三、设备驱动整体调用过程3.1 上层用户操控设备的流程&#xff1a;3.2…

[译] K8s和云原生

本篇内容是根据2019年8月份Kubernetes and Cloud Native音频录制内容的整理与翻译, Johnny 和 Mat 与 Kris Nova 和 Joe Beda 一起探讨了 Kubernetes 和云原生。他们讨论了 Kubernetes 推动的“云原生”应用的兴起、使用 Kubernetes 的合适场合、运行如此大型的开源项目所面临…

云服务器(华为云)安装java环境。

这篇文章主要是介绍如何搭建华为云服务器中的java环境&#xff0c;也就是jdk的安装。 这里华为云服务器使用的是liunx系统。 uname -a Linux操作系统的版本信息。具体来说&#xff0c;它表明使用的是Ubuntu系统&#xff0c;内核版本是5.15.0&#xff0c;构建于2023年1月20日&a…

linux配置git

一、生成新的 SSH 密钥 ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 按照提示操作&#xff1a; 当提示 Enter file in which to save the key (/root/.ssh/id_rsa): 时&#xff0c;直接按回车键使用默认路径。 当提示 Enter passphrase (empty for no p…

基于Java+Jsp+SpringMVC漫威手办商城系统设计和实现

基于JavaJspSpringMVC漫威手办商城系统设计和实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &am…

pycharm下载selenium等软件包时提示下载超时

1.问题描述 我今天在pycharm运行刚写的自动化脚本时&#xff0c;提示selenium模块未导入&#xff08;自动到导入&#xff09;&#xff0c;鼠标移动到【from selenium import webdriver]的selenium时&#xff0c;显示【未存在文档】 2 解决办法 文件--设置--项目&#xff1a;当前…

手写SpringMVC(简易版)

在上一篇博客中说到这里我们要进行手写SpringMVC&#xff0c;因此最好是将上一篇博客中的SpringMVC源码分析那一块部分搞懂&#xff0c;或者观看动力节点老杜的SpringMVC源码分析再来看这里的书写框架。 首先我们要知道对于一个完整系统的参与者&#xff08;即一个完整的web项…

CentOS 安装 JAVA环境(JDK 1.8)

镜像选择 推荐国内镜像直接下载 清华镜像 https://mirrors.tuna.tsinghua.edu.cn/Adoptium 关于重命名 AdoptOpenJDK 镜像为 Adoptium 的通知 编程宝库 http://www.codebaoku.com/jdk/jdk-index.html 这个镜像站&#xff0c;包含Oracle JDK、OpenJDK、AdoptOpenJDK、阿里…

Android平台使用VIA创建语音交互应用

Android平台使用VIA创建语音交互应用 概述 在 Android 平台上开发一款语音助手应用需要整合多种技术,包括语音识别(ASR)、文字转语音(TTS)、以及热词检测(Hotword Detection)。这些技术共同构成了语音助手应用的核心交互方式,使用户能够通过语音命令与设备进行无缝交…

Maya学习笔记:物体的层级关系

文章目录 父子关系设置父子关系同时显示两个大纲视图 组 父子关系 设置父子关系 设置父子物体&#xff1a; 方法1 先选择子物体&#xff0c;按住shift再选中父物体&#xff0c;按P或者G键 方法2 在大纲视图中按住鼠标中间&#xff0c;拖动一个物体到另一个物体上 取消父子关…

公安局软件管理平台建设方案和必要性,论文-———未来之窗行业应用跨平台架构

一、平台方略 由于csdn拦截关键信息&#xff0c;我发发布方案&#xff0c;请留意后面文章

Oracle逻辑备份脚本【生产环境适用】

1 说明 从Oracle10g开始&#xff0c;引入了数据泵&#xff08;Data Pump&#xff09;&#xff0c;是一种高效的数据传输工具&#xff0c;它通过导出&#xff08;Export&#xff09;和导入&#xff08;Import&#xff09;的方式帮助用户迁移数据。 在Oracle的产品设计中&#…

详解机器学习经典模型(原理及应用)——K-Means

一、K-Means算法概念 K-Means 算法是一种经典的聚类分析方法&#xff0c;属于无监督学习的一种。它的目标是将数据集中的样本划分为预定数量的簇&#xff0c;使得簇内的样本尽可能相似&#xff0c;而簇间的样本尽可能不同。K-Means在业务中也有诸多用途&#xff0c;比如在进行探…

Github + Hexo + Shoka搭建个人博客以及遇到的部分问题

博客预览&#xff1a; 主页&#xff1a; 文章&#xff1a; 博客语言链接&#xff1a; 全部分类 |mmjon 不在能知&#xff0c;乃在能行 Shoka官方博客&#xff1a; Yume Shoka 優萌初華 有夢書架 (lostyu.me) 1、准备 1、github账号 &#xff1a;自行去github官网注册…

睡眠监测系统基于边缘计算和微服务缓存

这篇论文的主要内容是关于基于边缘计算和微服务缓存的睡眠监测系统。以下是详细内容概述&#xff1a; 标题 睡眠监测系统基于边缘计算和微服务缓存 作者 Nico Surantha - 东京市立大学&#xff0c;日本David Jayaatmaja - 雅加达Bina Nusantara大学&#xff0c;印度尼西亚S…