最新要闻
- 世界视讯!盐城供电开发区供服中心:精准治理线损 助力提质增效
- 电壁挂炉取暖十大品牌_电壁挂炉十大品牌_全球快播
- 世界快资讯丨黄金树_黄金树立誓
- 销量连年下滑 上汽大众第一工厂永久关停?官方回应
- 白色攒机首选!七彩虹CVN B650 GAMING FROZEN V14主板图赏
- 男孩被撞身亡母亲因“太冷静”被网暴跳楼!这有错吗? 最新
- 淄博一烧烤城20多家商户为考生闭店 商户:烧烤城空荡荡但很值得
- 高三生考前在教室门口排队顶粽子:美好寓意“高中”
- 大宗交易:东望时代成交3172.5万元,折价0.22%(06-06) 快看
- 快资讯:西媒:皇马有意黄潜右边锋楚克乌泽 本赛季13球11助 3次攻破皇马
- 播报:罗马诺:皇马已向纳乔发送续约文件,球员告知国米他不会加盟
- 辽宁省62个地理标志产品入选《中国地理标志产品英文宣传册》 每日快播
- 凌志软件(688588)6月6日主力资金净卖出1159.81万元 当前视点
- 焦点速看:专家共话未成年人数据保护,小天才分享内容安全保护等功能设计!
- vlc设置访问输出模块为ftp教程
- 每日消息!价格超3万元 Mac Studio明天预售:苹果最强芯片M2 Ultra加持
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Spring框架中事务控制的运行原理|全球速递
Photo by Tomasz Filipek from Pexels: https://www.pexels.com/photo/nature-photography-of-flower-field-1646178/
Spring Transaction 基本介绍
我们在日常开发中经常使用Spring框架来实现事务管理。事务管理是指在执行一系列操作时,保证这些操作要么全部成功,要么全部失败,不会出现中间状态。事务管理可以保证数据的一致性和完整性,避免因为异常或错误导致的数据损坏。
Spring框架中的事务管理有两种实现方式:编程式事务管理和 声明式事务管理。编程式事务管理是指在代码中显式地控制事务的开始、提交和回滚,这种方式需要编写大量的重复代码,而且容易出错。声明式事务管理是指通过注解或配置文件来声明哪些方法需要进行事务控制,这种方式更简洁、灵活和优雅,也是Spring框架推荐的方式。
(相关资料图)
无论是哪种方式,Spring框架中的事务管理都是基于AOP(面向切面编程)的代理机制实现的。这让我们可以在不修改原有代码的情况下,为某些方法添加额外的功能或行为,比如日志、安全、缓存等。
声明式事务管理的基本使用
当我们使用声明式事务管理时,我们可以通过 @Transactional
注解来标注哪些方法需要进行事务控制,并且可以指定该注解的属性来设置事务的属性。例如:
@Servicepublic class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, timeout = 10) public void transferMoney(int fromId, int toId, double amount) { userDao.decreaseMoney(fromId, amount); userDao.increaseMoney(toId, amount); }}
上面的代码表示transferMoney
方法需要进行事务控制,并且设置了传播行为为REQUIRED
(表示如果当前没有事务,则创建一个新的事务,如果当前已经有事务,则加入该事务),隔离级别为READ_COMMITTED
(表示只能读取已经提交的数据,可以避免脏读,但不能避免不可重复读和幻读),超时时间为10秒(表示如果该方法执行超过10秒,则自动回滚事务)。
当Spring框架扫描到@Transactional
注解时,它会根据注解的属性创建一个 TransactionDefinition
对象,并且会为被注解的类生成一个代理对象,该代理对象会实现和目标类相同的接口,并且会拦截目标类的所有方法。当调用被注解的方法时,代理对象会先从Spring容器中获取一个事务管理器,并且根据 TransactionDefinition
对象获取一个事务状态(TransactionStatus
)对象,该对象包含了事务的信息和状态。然后代理对象会执行目标方法,如果目标方法正常返回,则代理对象会调用事务管理器的commit方法来提交事务;如果目标方法抛出异常,则代理对象会调用事务管理器的rollback方法来回滚事务。这样就实现了对目标方法的事务控制。
事务的传播行为
事务传播行为(Transaction Propagation)定义了一个事务方法与其他事务方法的关系,即当一个事务方法被调用时,如何处理现有的事务。在Spring框架中,可以通过设置@Transactional
注解的propagation
属性来指定事务传播行为。常用的事务传播行为包括:
- REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。这是最常用的传播行为。
- REQUIRES_NEW:无论当前是否存在事务,都创建一个新的事务。如果存在当前事务,会将当前事务挂起。
- SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。支持事务但不强制要求。
- NOT_SUPPORTED:以非事务方式执行操作,如果存在当前事务,则将其挂起。
- MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- NEVER:以非事务方式执行操作,如果存在当前事务,则抛出异常。
- NESTED:如果当前存在事务,则在嵌套事务中执行。如果当前没有事务,则创建一个新事务。嵌套事务是当前事务的一部分,具有独立的保存点,可以进行回滚。
事务隔离级别
事务隔离级别(Transaction Isolation)定义了事务之间的隔离程度,即一个事务对其他事务的可见性。在Spring框架中,可以通过设置@Transactional
注解的isolation
属性来指定事务隔离级别。常用的事务隔离级别包括:
- DEFAULT(默认):使用底层数据库的默认隔离级别。
- READ_UNCOMMITTED:允许读取未提交的数据,可能会导致脏读、不可重复读和幻读。
- READ_COMMITTED:只允许读取已提交的数据,可以防止脏读,但仍可能出现不可重复读和幻读。
- REPEATABLE_READ:确保在同一事务中多次读取数据时结果始终一致,可以防止脏读和不可重复读,但仍可能出现幻读。
- SERIALIZABLE:事务串行执行,确保所有并发事务都看到相同的数据状态,可以防止脏读、不可重复读和幻读。
需要注意的是,隔离级别越高,事务的并发性能可能会降低,因为需要锁定更多的资源以保证数据的一致性。
其他事务属性
在Spring Framework中,事务传播行为和隔离级别是事务管理的两个重要概念。它们决定了事务方法与其他事务方法之间的关系以及并发事务之间的相互影响。除此之外,还有一些常用设置如下
- 事务的超时时间:定义了一个事务允许执行的最长时间
- 事务的只读标志:定义了一个事务是否只进行查询操作,而不进行修改操作
- 事务的回滚规则:定义了哪些异常会导致事务回滚,哪些异常不会导致事务回滚
。。。。
声明式事务管理的原理分析
通过上面的分析,我们可以看到Spring框架中事务控制的运行原理是基于AOP代理机制实现的,它可以在不修改原有代码的情况下,为指定的方法添加事务控制的逻辑。这样可以大大简化我们的编程工作,也可以提高我们的代码质量和可维护性。
讲解完基本的使用方法,下面我们一起深入源码来探寻事务控制的原理。下面是一个简化的伪代码,用来说明Spring框架中声明式事务管理的运行原理:
// 生成的代理对象public class UserServiceImplProxy implements UserService { // 目标对象 private UserServiceImpl target; // 事务管理器 private PlatformTransactionManager transactionManager; // 事务定义 private TransactionDefinition transactionDefinition; public void transferMoney(int fromId, int toId, double amount) { // 获取事务状态 TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition); try { // 调用目标方法 target.transferMoney(fromId, toId, amount); // 提交事务 transactionManager.commit(transactionStatus); } catch (Exception e) { // 回滚事务 transactionManager.rollback(transactionStatus); // 抛出异常 throw e; } }}
Spring框架中事务管理的核心接口和类
在事务控制模块中一些重要的概念实现如下:
- PlatformTransactionManager接口:定义了事务管理器的基本操作
- DataSourceTransactionManager类:实现了基于JDBC的事务管理器
- JpaTransactionManager类:实现了基于JPA的事务管理器
- TransactionDefinition接口:定义了事务的属性和配置
- TransactionStatus接口:定义了事务的状态和信息
- TransactionInterceptor:AOP事务方法拦截器
Spring框架提供了一个接口 PlatformTransactionManager
来定义事务管理器的基本操作,比如获取事务状态、提交事务和回滚事务。不同的数据源需要实现不同的事务管理器,比如 JDBC 对应的是 DataSourceTransactionManager
,JPA对应的是 JpaTransactionManager
等。
从类图上来观察继承关系
Spring框架还提供了一个接口TransactionDefinition
来定义事务的属性,比如传播行为(propagation)、隔离级别(isolation)、超时时间和只读标志等。
事务管理的核心逻辑:Transaction Interceptor
当我们理解了本小节开头的伪代码时,再来看TransactionInterceptor
内的实现会发现其实Spring的事务管理模块并不复杂,由于它实现了MethodInterceptor
所以直接看invoke
方法,可以看到调用了父类的invokeWithinTransaction
方法
@Override@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport"s invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() { @Override @Nullable public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } @Override public Object getTarget() { return invocation.getThis(); } @Override public Object[] getArguments() { return invocation.getArguments(); } });}
进入 invokeWithinTransaction
方法内,可以观察到其整体逻辑是和我们之前分析的伪代码类似的:
@Nullableprotected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final TransactionManager tm = determineTransactionManager(txAttr); if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) { // 省略响应式事务管理的逻辑 } PlatformTransactionManager ptm = asPlatformTransactionManager(tm); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } commitTransactionAfterReturning(txInfo); return retVal; }....}
暂且不要深入到嵌套方法内的细节,上述代码的整体逻辑为:
- 获取事务管理器
- 视情况创建事务
- 执行业务方法
- 当捕捉到异常判断是否回滚处理
- 无异常时判断是否提交处理
看完了整体,再深入到细节。在AbstractPlatformTransactionManager.getTransaction
方法体内,我们可以看到事务隔离级别的实现方式,源码中用了多个条件判断来控制不同隔离级别时事务的行为:
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { // Use defaults if no transaction definition given. TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); Object transaction = doGetTransaction(); boolean debugEnabled = logger.isDebugEnabled(); if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. return handleExistingTransaction(def, transaction, debugEnabled); } // Check definition settings for new transaction. if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()); } // No existing transaction found -> check propagation behavior to find out how to proceed. if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation "mandatory""); } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def); } try { return startTransaction(def, transaction, debugEnabled, suspendedResources); } catch (RuntimeException | Error ex) { resume(null, suspendedResources); throw ex; } } else { // Create "empty" transaction: no actual transaction, but potentially synchronization. if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def); } boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null); }}
在TransactionAspectSupport.completeTransactionAfterThrowing
方法内,可以观察当捕捉到异常判断是否回滚处理的逻辑:
/** * Handle a throwable, completing the transaction. * We may commit or roll back, depending on the configuration. * @param txInfo information about the current transaction * @param ex throwable encountered */protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } } else { // We don"t roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by commit exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by commit exception", ex); throw ex2; } } }}
最后则是在 TransactionAspectSupport.commitTransactionAfterReturning
方法中成功执行事务的提交逻辑:
/** * Execute after successful completion of call, but not after an exception was handled. * Do nothing if we didn"t create a transaction. * @param txInfo information about the current transaction */protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]"); } txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); }}
注意事项及最佳实践
下面是一些使用Spring框架进行事务控制时需要注意的问题:
@Transactional
注解默认只对RuntimeException
和Error
进行回滚,对其他异常不进行回滚。如果需要对其他异常进行回滚,可以通过设置注解的rollbackFor
属性来指定。@Transactional
注解只能应用在 public 方法上,对于private、protected
或default
方法无效。这是因为Spring框架默认使用JDK动态代理来生成代理对象,而JDK动态代理只能拦截public方法。如果需要拦截非public方法,可以通过设置Spring容器的aop:config
标签的proxy-target-class属性为true,让Spring框架使用CGLIB动态代理来生成代理对象,在Spring Boot中则默认启用此属性。CGLIB动态代理是通过继承目标类来生成子类作为代理对象,因此可以拦截非public方法。@Transactional
注解只能对外部调用有效,对于同一个类中的内部调用无效。这是因为同一个类中的内部调用并没有经过代理对象,而是直接调用了目标方法,因此无法触发AOP拦截和增强。如果需要对内部调用也进行事务控制,可以通过使用ApplicationContext
或AutowireCapableBeanFactory
来获取当前类的代理对象,然后通过代理对象来调用内部方法。@Transactional
注解可以同时应用在接口、类和方法上,它们之间有继承和覆盖关系。- 注解的作用范围:如果在接口上使用注解,它将应用于所有实现该接口的类和方法。如果在类上使用注解,它将应用于该类中的所有方法。如果在方法上使用注解,它将仅应用于该方法。
- 继承关系:当一个类继承另一个类时,子类继承了父类的
@Transactional
注解。但是,子类可以选择覆盖父类的注解,并使用自己的注解配置。这意味着子类可以通过覆盖注解来修改事务的传播行为、隔离级别等属性。
在日常的开发中,也最好遵循一些业界探索出的实践经验,以确保事务的正确管理和数据的一致性:
- 明确标记事务边界:使用
@Transactional
注解明确标记需要进行事务管理的方法。将注解放在方法上,以确保在方法执行期间启用事务管理。 - 设置适当的事务传播行为和隔离级别:根据业务需求,选择适当的事务传播行为和隔离级别。确保在不同的方法调用中正确管理事务的传播和隔离。
- 限制事务作用范围:将事务的作用范围限制在需要进行事务管理的最小代码块上,而不是整个方法或类。这样可以减少锁定资源的时间和范围,提高并发性能。
- 避免长时间事务:长时间事务会占用数据库资源并降低系统性能。尽量将事务的执行时间控制在合理的范围内,避免长时间的事务操作。
- 捕获并处理异常:在事务方法中捕获并处理异常是必要的。根据业务需求,选择适当的处理方式,如回滚事务、记录日志或抛出自定义异常。
- 尽量避免嵌套事务:嵌套事务会增加事务管理的复杂性,并可能导致死锁等并发问题。除非必要,尽量避免使用嵌套事务。
- 注意事务的回滚规则:通过设置
rollbackFor
属性,明确指定哪些异常会触发事务的回滚。确保异常的正确处理和事务的正确回滚。 - 定期进行性能调优和监控:对于事务频繁的应用程序,定期进行性能调优和监控是必要的。通过监控事务执行时间、数据库锁定情况等指标,优化事务管理和数据库设计。
- 编写单元测试验证事务管理:编写单元测试来验证事务管理的正确性。使用Spring的测试框架和事务支持来模拟数据库操作和事务回滚,确保事务管理的正确性。
总之,良好的事务管理实践可以确保数据的一致性和事务的正确执行。遵循上述最佳实践和注意事项,可以提高系统的稳定性和性能。
关键词:
Spring框架中事务控制的运行原理|全球速递
世界视讯!盐城供电开发区供服中心:精准治理线损 助力提质增效
多地金融监管开展调研 摸底信贷需求、房地产市场、金融风险变化等情况 每日速递
电壁挂炉取暖十大品牌_电壁挂炉十大品牌_全球快播
世界快资讯丨黄金树_黄金树立誓
销量连年下滑 上汽大众第一工厂永久关停?官方回应
白色攒机首选!七彩虹CVN B650 GAMING FROZEN V14主板图赏
男孩被撞身亡母亲因“太冷静”被网暴跳楼!这有错吗? 最新
淄博一烧烤城20多家商户为考生闭店 商户:烧烤城空荡荡但很值得
高三生考前在教室门口排队顶粽子:美好寓意“高中”
大宗交易:东望时代成交3172.5万元,折价0.22%(06-06) 快看
快资讯:西媒:皇马有意黄潜右边锋楚克乌泽 本赛季13球11助 3次攻破皇马
ESMap 三维地图引擎在公路隧道的应用 - 智慧公路隧道数字孪生
STM32F429 Discovery开发板应用:实现USB虚拟串口(VPC)
关于SQL语句中-使用正则的方式匹配-排除包含任意字母点两个字符的字符串
播报:罗马诺:皇马已向纳乔发送续约文件,球员告知国米他不会加盟
辽宁省62个地理标志产品入选《中国地理标志产品英文宣传册》 每日快播
每日机构分析:6月6日_全球关注
凌志软件(688588)6月6日主力资金净卖出1159.81万元 当前视点
焦点速看:专家共话未成年人数据保护,小天才分享内容安全保护等功能设计!
vlc设置访问输出模块为ftp教程
每日消息!价格超3万元 Mac Studio明天预售:苹果最强芯片M2 Ultra加持
全球快看:小鹏找林志颖代言是不是好点子?高管回应:当然是
苹果Vision Pro头显会颠覆XR行业吗?HTC王雪红:重大分水岭_天天消息
全电池驱动、零污染 我国新能源轻轨车辆首次出口海外-全球快讯
行业首创双水泵!超频三金刚双擎DE水冷散热器图赏 天天信息
越博动力业绩预告不准确,公司及财务总监收警示函-每日看点
每日热文:满负荷生产是什么意思计算公式(猪场满负荷生产是什么意思)
上行动能走弱 债市调整压力渐显
厦门疾控:本月谨防登革热和手足口病
全日空首席执行官希望增加波音787订购数量
天天时讯:易基因:小檗碱通过介导m6A mRNA甲基化调控斑马鱼肝细胞氧化应激、凋亡和自噬
Vue2知识点简要
一朝学信奥,十年也难跑
当前观点:Unity框架中的核心类
近13万汉藏对照词典汉藏翻译ACCESS\EXCEL数据库
广西发改委:地方政府不对国企债务承担偿债责任-当前热讯
做好“加减法” 增粮有实招——部分粮食主产区一线扫描
香港总商会将香港今年GDP增长预测上调至4.2%
环球观天下!祝高考生前程似锦的句子
特斯拉索赔500万元案开庭 车顶维权女车主当庭反诉
卢伟冰给高考生几个小建议 米粉看完后信心满满_当前看点
全球观天下!河北一过山车停电多名游客倒挂半空:备用电源启用后均平安下车
你买了吗?广东一公司进口日本核辐射食品被罚1万:大多已售出
世界热点!电梯突发故障丈夫下意识护妻儿:家人身体无大碍
中国气象局:我国已进入主汛期和灾害多发期 要加强临灾预警
java springboot整合elasticsearch时关于LocalDateTime处理的方式
昇腾实战丨DVPP媒体数据处理图片解码问题案例
每日头条!实际薪资水平低迷引发前景担忧 日债收益率周二普遍回落
【新华500】新华500指数(989001)6日跌1%
最高可抵6000元!苹果宣布Mac Studio等设备加入换购计划
今日讯!大厂中第一个对标ChatGPT 百度文心一言2个月来性能已提高50倍
拼了!35岁男子为考清华复读14年:没浪费教育资源 奖金仅够生活-天天快播
淄博夜空500架无人机助力高考:为学子加油 当前速递
聚焦:“牧马人同款大皮卡”全新Jeep角斗士谍照曝光
科林电气:中标3个国家电网采购项目,中标总金额约9475万元_新动态
环球观天下!在 Windows 系统上,你可以使用 Certbot 生成 Let's Encrypt 的泛域名证书。以下是具体步骤
焦点速看:如何让你的结构体更高效
【专为苛刻的数据环境而构建】上海道宁为您带来世界上先进的矢量原生、时间序列和实时分析数据库——kdb系列产品|世界新消息
天天快消息!提升生产线效率与质量:智慧工厂的优势与应用
Java-模板生成PDF方式2-PDFBox
智慧医疗让看病更便捷-新资讯
马斯克扔下车圈核弹:特斯拉FSD可以给其他车企用!-每日热点
小米又一爆款诞生!小米手环8国内出货破110万:上市不到俩月 全球短讯
价值或达500亿 国铁大规模采购动车组:350公里时速复兴号就有103组
疑似比亚迪F品牌官方账号成立:名为“方程豹汽车”
奇瑞杀疯了!5月销量近14万辆 一路反超吉利、长城
世界热讯:电解槽和氢能矿卡上榜内蒙古2023年技术装备首台(套)名单
Web安全-渗透测试-基础知识03
小学生发现深沟露出车轮救人一命被网友点赞心细:老人驾老头乐失控导致
天天热点评!全球第一套!龙芯2K1500控制器不间断运行142天3408小时
喝酒去世网红家墙壁写着钱比命重要 网友唏嘘!家人:从没割过粉丝韭菜
“宇宙猜想”CTO叶云出席元宇宙论坛并发表演讲
新品未能提振股价,苹果概念股跌幅扩大,华兴源创、长盈精密跌超15% 环球快讯
饶派杯 XCTF 车联网挑战赛 mqttsvr 复现|当前观点
【天天速看料】一条视频带你回忆高三这一年 网友感动:祝愿每位考生忙而不茫
《暗黑破坏神4》正式发售:标准版终于能玩了
苹果Vision Pro头戴支持近视用户:需额外掏钱买插片-世界观焦点
牛骨头汤有营养吗 牛骨头汤是否有营养
读改变未来的九大算法笔记05_数字签名
Git hooks与自动化部署-全球新消息
每日聚焦:直播平台源码画面质量功能的实现
云图说|ModelArts开发环境,让AI开发、探索、教学更简单 世界新要闻
苹果XR头显Vision Pro王炸登场:3499美元起售,2024年开卖-环球观天下
经常挖鼻孔会影响颜值 严重可诱发颅内感染
天天观热点:小米王腾分享苹果Vision Pro看法:令人赞叹、但普及需要时间
QQ空间18周岁 第一代美女网红鼻祖露面:16年没变样
压力给到合资品牌 上汽大众永久关停第一工厂:部分产线搬迁|全球要闻
全国爱眼日,王贾桥小学倡导学子保护视力、珍爱光明
linux tar解压命令总结
速讯:848中国鱼类资料图谱大全ACCESS\EXCEL数据库
顶象无感验证码助力京客隆提升数字化运营能力
MySQL用户与权限管理_每日热门
全球快播:电池级碳酸锂价格重回30万元/吨 锂盐厂商二季度业绩可期
抄底!百度网盘超级会员年卡178元:送优酷+喜马拉雅 世界实时
防止别人蹭热点 苹果Vision Pro完全不提元宇宙三个字
16.99万起!零重力座椅、无框车门、三种动力选择 长安深蓝S7即将上市
制作成本16.5亿!《封神三部曲》第一部定档:7月20日上映 焦点速读
天天消息!孙俪代言!超能双离子洗衣粉骨折价大促:39.9元11斤
国内卫浴二线品牌有哪些_国内卫浴二线品牌-最新