本文来说下tx-lcn分布式事务框架

文章目录

  • LCN介绍
  • LCN解决方案
  • 事务控制原理
  • 核心步骤
  • 实战之-TxManager
    • 建中间件数据库
    • TM服务搭建
    • TM服务中 application.properties配置
    • 启动成功后界面
  • 实战之-TxClient
    • 场景简介
    • 服务结构
    • producer 服务
    • consumer 服务
    • 效果
  • 本文小结

LCN介绍

tx-lcn Github 地址:https://github.com/codingapi/tx-lcn

官方宣称:LCN并不生产事务,LCN只是本地事务的协调工。

TX-LCN定位于一款事务协调性框架,框架其本身并不操作事务,而是基于对事务的协调从而达到事务一致性的效果。


LCN解决方案

在一个分布式系统下存在多个模块协调来完成一次业务。那么就存在一次业务事务下可能横跨多种数据源节点的可能。TX-LCN将可以解决这样的问题。

例如存在服务模块A 、B、 C。A模块是mysql作为数据源的服务,B模块是基于redis作为数据源的服务,C模块是基于mongo作为数据源的服务。若需要解决他们的事务一致性就需要针对不同的节点采用不同的方案,并且统一协调完成分布式事务的处理。


若采用TX-LCN分布式事务框架,则可以将A模块采用LCN模式、B/C采用TCC模式就能完美解决。


事务控制原理

TX-LCN由两大模块组成, TxClient、TxManager,TxClient作为模块的依赖框架,提供TX-LCN的标准支持,TxManager作为分布式事务的控制方。事务发起方或者参与方都由TxClient端来控制。


核心步骤

创建事务组

是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。

加入事务组

添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。

通知事务组

是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。


实战之-TxManager

LCN官方文档中的快速开始,说实话,还真快速不了,首先咱们先看下官方文档怎么说的。

建中间件数据库

名称为: tx-manager,并创建表。

CREATE TABLE `t_tx_exception`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`transaction_state` tinyint(4) NULL DEFAULT NULL,`registrar` tinyint(4) NULL DEFAULT NULL,`remark` varchar(4096) NULL DEFAULT  NULL,`ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决',`create_time` datetime(0) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

TM服务搭建


将官方源码仓库中的txlcn-tm直接打包,然后运行即可,TM中间件就算搭起来了,如果直接把txlcn-tm拎出来,打包是打不成功的,因为txlcn-tm 依赖了其他的txlcn的其他服务,打包的话需要把其他包也一起打进去,我现在是直接本地导入IDE运行的,是可以的。


TM服务中 application.properties配置

现在可以使用yml文件来进行配置。

spring.application.name=TransactionManager
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8&usessl=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update#Redis配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=tx-lcn.manager.admin-key=lcn#spring.application.name=TransactionManager
#server.port=7970
#
## JDBC 数据库配置
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
#spring.datasource.username=root
#spring.datasource.password=123456
#
## 数据库方言
#spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
#
## 第一次运行可以设置为: create, 为TM创建持久化数据库表
#spring.jpa.hibernate.ddl-auto=validate
#
## TM监听IP. 默认为 127.0.0.1
#tx-lcn.manager.host=127.0.0.1
#
## TM监听Socket端口. 默认为 ${server.port} - 100
#tx-lcn.manager.port=8070
#
## 心跳检测时间(ms). 默认为 300000
#tx-lcn.manager.heart-time=300000
#
## 分布式事务执行总时间(ms). 默认为36000
#tx-lcn.manager.dtx-time=8000
#
## 参数延迟删除时间单位ms  默认为dtx-time值
#tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}
#
## 事务处理并发等级. 默认为机器逻辑核心数5倍
#tx-lcn.manager.concurrent-level=160
#
## TM后台登陆密码,默认值为codingapi
#tx-lcn.manager.admin-key=codingapi
#
## 分布式事务锁超时时间 默认为-1,当-1时会用tx-lcn.manager.dtx-time的时间
#tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}
#
## 雪花算法的sequence位长度,默认为12位.
#tx-lcn.manager.seq-len=12
#
## 异常回调开关。开启时请制定ex-url
#tx-lcn.manager.ex-url-enabled=false
#
## 事务异常通知(任何http协议地址。未指定协议时,为TM提供内置功能接口)。默认是邮件通知
#tx-lcn.manager.ex-url=/provider/email-to/***@**.com#注意(NOTE)
#(1) TxManager所有配置均有默认配置,请按需覆盖默认配置。
#(2) 特别注意 TxManager进程会监听两个端口号,一个为TxManager端口,另一个是事务消息端口。TxClient默认连接事务消息端口是8070, 所以,为保证TX-LCN基于默认配置运行良好,请设置TxManager端口号为8069 或者指定事务消息端口为8070
#(3) 分布式事务执行总时间 a 与 TxClient通讯最大等待时间 b、TxManager通讯最大等待时间 c、微服务间通讯时间 d、微服务调用链长度 e 几个时间存在着依赖关系。 a >= 2c + (b + c + d) * (e - 1), 特别地,b、c、d 一致时,a >= (3e-1)b。你也可以在此理论上适当在减小a的值,发生异常时能更快得到自动补偿,即 a >= (3e-1)b - Δ(原因)。 最后,调用链小于等于3时,将基于默认配置运行良好
#(4) 若用tx-lcn.manager.ex-url=/provider/email-to/xxx@xx.xxx 这个配置,配置管理员邮箱信息(如QQ邮箱):
#spring.mail.host=smtp.qq.com
#spring.mail.port=587
#spring.mail.username=xxxxx@**.com

启动成功后界面


TxManager进程会监听两个端口号,一个为TxManager 7970 端口,另一个是事务消息端口 8070。


实战之-TxClient

场景简介

AB两个服务,A(producer)服务调用B(consumer)服务完毕后,抛出异常,B服务能回滚,确保幂等。

AB环境:MybatisPlus,Erueka,Feign,这些具体就不细讲了


服务结构


producer 服务

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"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.glj</groupId><artifactId>producer</artifactId><version>0.0.1-SNAPSHOT</version><name>producer</name><modelVersion>4.0.0</modelVersion><description>Demo project for Spring Boot</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><codingapi.txlcn.version>5.0.2.RELEASE</codingapi.txlcn.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>27.0-jre</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- mybatis-plus begin --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.6</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.8.0</version><exclusions><exclusion><artifactId>org.mapstruct</artifactId><groupId>mapstruct</groupId></exclusion></exclusions></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.8.0</version></dependency><dependency><groupId>com.codingapi.txlcn</groupId><artifactId>txlcn-tc</artifactId><version>${codingapi.txlcn.version}</version></dependency><dependency><groupId>com.codingapi.txlcn</groupId><artifactId>txlcn-txmsg-netty</artifactId><version>${codingapi.txlcn.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

application.yml

spring:application:name: spring-cloud-producerdatasource:url: jdbc:mysql://127.0.0.1:3306/spring_cloud_app?serverTimezone=GMT%2B8&characterEncoding=utf-8password: rootusername: rootdriver-class-name: com.mysql.cj.jdbc.Driverredis:host: 127.0.0.1port: 6379server:port: 8081eureka:client:service-url:defaultZone: http://glj:glj@127.0.0.1:2100/eureka/instance:prefer-ip-address: trueinstance-id: ${spring.cloud.client.ipAddress}:${server.port}#swagger
swagger2:enable: truetx-lcn:client:manager-address: 127.0.0.1:8070

服务入口

package com.glj.producer;import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableDistributedTransaction
public class ProducerApplication {public static void main(String[] args) {SpringApplication.run(ProducerApplication.class, args);}}

服务实现类

package com.glj.producer.business.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.glj.producer.business.entity.UserPo;
import com.glj.producer.business.mapper.UserMapper;
import com.glj.producer.business.service.IUserService;
import com.glj.producer.client.ConsumerUserClinet;
import com.glj.producer.dto.ProducerRequst;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** <p>*  服务实现类* </p>** @author * @since 2031-8-4*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, UserPo> implements IUserService {@Autowiredprivate ConsumerUserClinet consumerUserClinet;@Autowiredprivate IUserService userService;/*** 使用分布式事务* @param requst* @return*/@Override@LcnTransaction@Transactionalpublic String aTob(ProducerRequst requst) {log.info("开始调用B服务");Boolean res =  consumerUserClinet.saveUser(requst.getNickName(),requst.getId());log.info("B服务return result{}",res);UserPo userPo = userService.getById(requst.getId());userPo.setUserName(requst.getNickName());userService.saveOrUpdate(userPo);Preconditions.checkArgument(StringUtils.isNotBlank(requst.getExFlag()),"exFlag is null");if(res) {return "scuess";} else {return  "false";}}/*** 未使用分布式事务* @param requst* @return*/@Override@Transactionalpublic String aTob1(ProducerRequst requst) {log.info("开始调用B服务");Boolean res =  consumerUserClinet.saveUser1(requst.getNickName(),requst.getId());log.info("B服务return result{}",res);UserPo userPo = userService.getById(requst.getId());userPo.setUserName(requst.getNickName());userService.saveOrUpdate(userPo);Preconditions.checkArgument(StringUtils.isNotBlank(requst.getExFlag()),"exFlag is null");if(res) {return "scuess";} else {return  "false";}}
}

前端控制器

package com.glj.producer.business.controller;import com.glj.producer.business.service.IUserService;
import com.glj.producer.dto.ProducerRequst;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** <p>*  前端控制器* </p>*  * @author * @since 2021-08-04*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;@ApiOperation(value = "A 服务调用B服务(使用分布式事务)")@PostMapping("/aTob")public String aTob(@RequestBody ProducerRequst requst){return userService.aTob(requst);}@ApiOperation(value = "A 服务调用B服务(未使用分布式事务)")@PostMapping("/aTob1")public String aTob1(@RequestBody ProducerRequst requst){return userService.aTob1(requst);}
}

其实就是这么简单,核心代码就三处

  • 一处是服务入口加注解@EnableDistributedTransaction
  • 一处是service方法上加注解 @LcnTransaction
  • 另一处是application.yml 指定事务消息端口

consumer 服务

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><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.glj</groupId><artifactId>consumer</artifactId><version>0.0.1-SNAPSHOT</version><name>consumer</name><description>Demo project for Spring Boot</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><codingapi.txlcn.version>5.0.2.RELEASE</codingapi.txlcn.version><springcloud.version>Greenwich.RELEASE</springcloud.version><swagger-version>2.8.0</swagger-version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.6</version><exclusions><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- 与swagger一起使用,需要注意--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.8.0</version><exclusions><exclusion><artifactId>org.mapstruct</artifactId><groupId>mapstruct</groupId></exclusion></exclusions></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>${swagger-version}</version></dependency><dependency><groupId>com.codingapi.txlcn</groupId><artifactId>txlcn-tc</artifactId><version>${codingapi.txlcn.version}</version></dependency><dependency><groupId>com.codingapi.txlcn</groupId><artifactId>txlcn-txmsg-netty</artifactId><version>${codingapi.txlcn.version}</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>27.0-jre</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${springcloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

服务入口

package com.glj.consumer;import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
@EnableDistributedTransaction
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}

服务实现类

package com.glj.consumer.business.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.glj.consumer.business.entity.SysUserPo;
import com.glj.consumer.business.mapper.SysUserMapper;
import com.glj.consumer.business.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** <p>*  服务实现类* </p>** @author * @since 2021-08-04*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserPo> implements ISysUserService {/*** LCN实现分布式事务* @param nickName* @param Id* @return*/@Override@Transactional@LcnTransactionpublic Boolean saveUser(String nickName,Long Id){SysUserPo user = this.getById(Id);user.setNickname(nickName);return this.saveOrUpdate(user);}/*** 未实现分布式事务* @param nickName* @param Id* @return*/@Override@Transactionalpublic Boolean saveUser1(String nickName,Long Id){SysUserPo user = this.getById(Id);user.setNickname(nickName);return this.saveOrUpdate(user);}
}

还是那句话,就这么简单,跟生产者同样三处


效果



结果表明使用分布式以后,异常后数据回滚。没有使用分布式,异常后,AB数据不一致


本文小结

LCN只是解决分布式事务的第三方,目前阿里的GTS 也很成熟了,后期将继续为大家分解通过GTS怎么解决分布式事务问题。现在改名叫做seata框架,以后估计是解决分布式事务的一个热门解决方案。

关于tx-lcn分布式事务框架的几个问题相关推荐

  1. LCN分布式事务框架实战

    本文来写个LCN分布式事务框架实战例子 文章目录 概述 概述 lcn分布式事务教程https://www.codingapi.com/docs/txlcn-preface/

  2. LCN分布式事务框架解决分布式事务一致性问题

    LCN分布式事务框架 框架介绍 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果. 核心步骤 创建事务组 是指在事务发起方开始执行业务代码之前先调用TxMana ...

  3. LCN分布式事务框架

    1.LCN是什么 LCN是国产开源的分布式事务处理框架.LCN即:lock(锁定事务单元).confirm(确认事务模块状态).notify(通知事务). 官网:http://www.txlcn.or ...

  4. 分布式事务(二)LCN分布式事务框架

    1. 简介 LCN框架在2017年6月发布第一个版本,目前最新已经达到5.0版本. LCN早期设计时,1.0版本和2.0版本设计步骤如下: 锁定事务单元(Lock) 确认事务模块状态(Confirm) ...

  5. SpringCloud(7) LCN分布式事务框架入门

    官网:http://www.txlcn.org/ LCN原理:https://github.com/codingapi/tx-lcn/wiki/LCN%E5%8E%9F%E7%90%86 入门测试: ...

  6. SpringCloud - LCN分布式事务框架

    官网:http://www.txlcn.org/ LCN原理:https://github.com/codingapi/tx-lcn/wiki/LCN%E5%8E%9F%E7%90%86 入门测试: ...

  7. LCN 分布式事务框架

    1.LCN 框架的由来 在设计框架之初的1.0 ~ 2.0的版本时,框架设计的步骤是如下的,各取其首字母得来的LCN命名: 锁定事务单元(lock) 确认事务模块状态(confirm) 通知事务( n ...

  8. 基于SpringCloud的分布式事务框架(LCN)

    框架特点 支持各种基于spring的db框架 兼容springcloud.dubbo 使用简单,代码完全开源 基于切面的强一致性事务框架 高可用,模块可以依赖dubbo或springcloud的集群方 ...

  9. 分布式事务框架lcn入门demo

    文章目录 简介 实现原理 入门demo 简介 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果. LCN5.0.2有3种模式,分别是LCN模式,TCC模式,TX ...

  10. SpringBoot-LCN5.0.2分布式事务框架整合

    LCN分布式事务框架整合 场景图:我们是要在订单服务中,调用库存服务.当下一个订单的时候,就对库存-1操作 1.首先要把tx-manager(分布式协调者)项目搭建起来 我这里使用的是最新的lcn版本 ...

最新文章

  1. js获取 日期 星期 时间
  2. Custom Url Helper for Zend View
  3. 【OpenCV入门指南】第五篇 轮廓检测 上
  4. 【云炬大学生创业基础笔记】第1章第1节 创新和创业有什么样的关系?
  5. 单片机串口通信电平不匹配的解决电路,5V 3.3V串口通讯
  6. 编程也讲禅,您读过《金刚经》吗?——ADO.NET核心类的灭度与SQLHelper的诞生——十八相送(上)...
  7. 【Java】java插件化开发
  8. 考研408复习思路,学习方法
  9. 厂房自控系统设计方案
  10. NRF52840 NRF52833 nRF5 SDK 开发
  11. 基于Springboot的物业管理系统_代码
  12. Word生成目录后,二级,三级目录页码处与一级目录不齐
  13. 景深的计算及弥散圆、光圈的概念
  14. 运动员等级查询系统C语言,中国运动员等级查询系统
  15. 1038: 绝对值最大 C语言
  16. Justinmind教程(3)——管理原型
  17. 唯品会密码JS解密与python登录!
  18. 微信小程序实现时间预约功能
  19. 如何安装KEIL并配置好51与STM32的环境
  20. 深入理解Pytorch负对数似然函数(torch.nn.NLLLoss)和交叉熵损失函数(torch.nn.CrossEntropyLoss)

热门文章

  1. OSChina 周五乱弹 ——发现办公室女同事走光了
  2. Fedora 17 安装视频
  3. 管理刀片服务器的KVM切换器
  4. 云南构建“健康医疗云框架”6项重点工程规范医疗大数据建设
  5. MySQL数据约束和关联查询
  6. 博客专题计划:《在实践中深入理解常见网络协议》
  7. java23中设计模式——行为模式——Chain of Responsibility(职责链)
  8. 交换机命令行配置与VLAN
  9. 关于T4,正在发生的...
  10. LeetCode 201. 数字范围按位与