当前位置: 首页 > news >正文

【工作中问题解决实践 七】SpringBoot集成Jackson进行对象序列化和反序列化

去年10月份以来由于公司和家里的事情太多,所以一直没有学习,最近缓过来了,学习的脚步不能停滞啊。回归正题,其实前年在学习springMvc的时候也学习过Jackson【Spring MVC学习笔记 五】SpringMVC框架整合Jackson工具,但是呢只是局限于基本用法,当时也刚进入新项目工作没多久,体会也没有那么深刻。现如今工作中深度用到了Jackson,但是对于Jackson的详细情况心里却没有十分的底,大多数时候都是用到的时候从网上找相关的方法实现copy一份,没有全局的认识,所以这篇博客详细的学习和实践一下Jackson。当然市面上的序列化框架有很多,例如谷歌的Gson,阿里的FastJson,但是因为综合考虑性能(Jackson比较强)、稳定性(Jackson和Gson都比较强),再加上SpringBoot默认集成的就是Jackson,所以对于Jackson掌握清楚后就足以应对大多数工作场景了。

回顾Json格式规则

从结构上看,所有的Json格式数据最终都可以分成三种类型:

  • 第一种类型是scalar(标量),也就是一个单独的string(字符串)或数字(numbers),比如"北京"这个单独的词
  • 第二种类型是sequence(序列),也就是若干个相关的数据按照一定顺序并列在一起,又叫做array(数组)或List(列表),比如["北京","天津"]
  • 第三种类型是mapping(映射),也就是一个名/值对(Name/value),即数据有一个名称,还有一个与之相对应的值,这又称作hash(散列)或dictionary(字典),比如{"城市名称":"北京"}

Json格式规则有如下几种:

  1. 并列的数据之间用逗号分隔
  2. 映射用冒号表示
  3. 并列数据的集合(数组)用方括号[]表示
  4. 映射的集合(对象)用大括号{}表示

大多时候我们会用到对象和Json的序列化与反序列化操作。

SpringBoot集成Jackson

当然第一步就是在Maven中进行Jackson包的引入了,还是从Maven的中央仓库引入最新版本的Jackson:Jackson的Maven仓库地址,我们就使用截止目前Jackson更新的最新版本:
在这里插入图片描述
pom文件如下:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version>
</dependency>

Jackson核心包概览

Jackson包含三部分的核心包:jackson-core、jackson-annotations、jackson-databind

  • jackson-core,核心包,提供基于流模式解析的相关 API,它包括 JsonPaserJsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  • jackson-annotations,注解包,提供标准注解功能;
  • jackson-databind ,数据绑定包, 提供基于对象绑定解析的相关 API ( ObjectMapper ) 和树模型 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。
    当然因为jackson-databind 依赖 jackson-corejackson-annotations,所以当添加 jackson-databind 之后, jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。

在这里插入图片描述
由于我们大多数场景都是处理对象和Json之间的映射关系,所以我们把重点放到对象绑定上来。

核心对象ObjectMapper

大多数的ObjectMapper对象都会被配置到Feature对象。
在这里插入图片描述
这篇文章ObjectMapper的一些配置提到的一些默认配置在最新的jackson版本里已经更新了,例如序列化时默认的时间戳格式被取消,序列化时默认的空对象异常也不会抛出了

Jackson基本用法实践

关于Jackson的基本用法如下,直接上代码清单

目标Person对象

我们用来测试的对象

package com.example.springboot.jackson;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;
import java.util.List;/*** The type Person.** @author tianmaolin004* @date 2023 /3/18*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Person {private String name;private Integer age;private List<String> interests;private LocalDate birthday;
}

JsonUtils类

包括ObjectMapper对象的初始化以及相关的一些配置,还有转换方法

package com.example.springboot.jackson;import com.alibaba.druid.util.StringUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;/*** The type Json operator.** @author tianmaolin004* @date 2023 /3/18*/
@Slf4j
public class JsonUtils {private static final ObjectMapper objectMapper = new ObjectMapper();private static final String LOCAL_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";static {// 1 序列化及反序列化的时间配置JavaTimeModule timeModule = new JavaTimeModule();timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_PATTERN)));timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_PATTERN)));objectMapper.registerModule(timeModule);objectMapper.setDateFormat(new SimpleDateFormat(LOCAL_DATE_TIME_PATTERN));//2 忽略反序列化时,对象不存在对应属性的错误,如果不存在该属性,则设置值为nullobjectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);//3 忽略序列化时值为Null元素,不存在该元素,则字符串中无该元素,而不是展示为nullobjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);}/*** 对象转字符串** @param <T> the type parameter* @param obj the obj* @return the string*/public static <T> String obj2Str(T obj) {if (obj == null) {return null;}try {return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);} catch (Exception e) {log.error("obj2Str fail");return null;}}/*** 字符串转对象** @param <T>   the type parameter* @param str   the str* @param clazz the clazz* @return the t*/public static <T> T str2Obj(String str, Class<T> clazz) {if (StringUtils.isEmpty(str) || clazz == null) {return null;}try {return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);} catch (Exception e) {log.error("str2Obj fail");return null;}}/*** 字符串转对象:泛型模式,一般用于集合** @param <T>           the type parameter* @param str           the str* @param typeReference the type reference* @return the t*/public static <T> T str2Obj(String str, TypeReference<T> typeReference) {if (StringUtils.isEmpty(str) || typeReference == null) {return null;}try {return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));} catch (Exception e) {log.error("str2Obj fail");return null;}}/*** 字符串转JsonNode** @param str the str* @return the json node*/public static JsonNode str2JsonNode(String str) {if (StringUtils.isEmpty(str)) {return null;}try {return objectMapper.readTree(str);} catch (Exception e) {log.error("str2Obj fail");return null;}}/*** 对象互转** @param <T>         the type parameter* @param fromValue   the from value* @param toValueType the to value type* @return the t*/public static <T> T convertValue(@NonNull Object fromValue, @NonNull Class<T> toValueType) {try {return objectMapper.convertValue(fromValue, toValueType);} catch (Exception e) {log.error("str2Obj fail");return null;}}/*** 对象互转泛型模式** @param <T>            the type parameter* @param fromValue      the from value* @param toValueTypeRef the to value type ref* @return the t*/public static <T> T convertValue(@NonNull Object fromValue, @NonNull TypeReference<T> toValueTypeRef) {try {return objectMapper.convertValue(fromValue, toValueTypeRef);} catch (Exception e) {log.error("str2Obj fail");return null;}}
}

测试Json转换

测试类及测试结果:

package com.example.springboot.jackson;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;/*** @author tianmaolin004* @date 2023/3/18*/
public class JsonTest {public static void main(String[] args) {// 序列化操作List<String> interests = new ArrayList<>();interests.add("跑步");interests.add("游泳");Person person = Person.builder().name("tml").age(24).interests(interests).birthday(LocalDate.now()).build();System.out.println("obj2Str,序列化对象");System.out.println(JsonUtils.obj2Str(person));Person personLoseAttr = Person.builder().name("tml").interests(interests).birthday(LocalDate.now()).build();System.out.println("obj2Str,序列化缺失元素对象");System.out.println(JsonUtils.obj2Str(personLoseAttr));Person emptyPerson = new Person();System.out.println("obj2Str,序列化空对象");System.out.println(JsonUtils.obj2Str(emptyPerson));// 反序列化操作String personStr = "{\"name\":\"wc\",\"age\":99,\"interests\":[\"跑步\",\"游泳\",\"唱跳\",\"rapper\",\"打游戏\"],\"birthday\":\"2023-03-05\"}";System.out.println("str2Obj,反序列化对象");System.out.println(JsonUtils.str2Obj(personStr, Person.class));System.out.println("str2Obj,反序列化对象,由于字符串不符合Json的mapping格式,所以需要特殊判断");System.out.println(JsonUtils.str2Obj("北京", String.class));System.out.println("str2Obj,反序列化对象,由于集合不能指定元素类型,所以使用泛型方式");System.out.println(JsonUtils.str2Obj("[\"跑步\",\"游泳\",\"唱跳\",\"rapper\",\"打游戏\"]", new TypeReference<List<String>>() {}));String personLoseAttrStr = "{\"age\":99,\"interests\":[\"跑步\",\"游泳\",\"唱跳\",\"rapper\",\"打游戏\"]}";System.out.println("str2Obj,反序列化缺失元素的对象");System.out.println(JsonUtils.str2Obj(personLoseAttrStr, Person.class));String personBadAttrStr = "{\"ag\":99,\"interests\":[\"跑步\",\"游泳\",\"唱跳\",\"rapper\",\"打游戏\"]}";System.out.println("str2Obj,反序列化包含不存在元素的对象");System.out.println(JsonUtils.str2Obj(personBadAttrStr, Person.class));// 反序列化为jsonNode对象,获取属性值并将属性值转为目标类型对象:场景,目标JSON结构复杂,不想映射创建一个对象,只想使用其中部分数据,则先将JSON转为JsonNode对象,获取其部分属性值再转为我们需要的确定性对象System.out.println("str2JsonNode,反序列化JsonNode对象");JsonNode jsonNode = JsonUtils.str2JsonNode(personStr);System.out.println(jsonNode);System.out.println(jsonNode.findValues("age"));System.out.println(JsonUtils.convertValue(jsonNode.get("interests"), new TypeReference<List<String>>() {}));System.out.println(JsonUtils.convertValue(jsonNode.get("name"), String.class));}
}

打印结果如下:
在这里插入图片描述

应用场景:深拷贝

对于List中存在对象的情况下除了循环遍历,对每个元素重建外,通过序列化的方式也能轻松的实现集合的深拷贝

 List<FeeRateDiscount> resultPlatDiscount = BeanCopyUtils.deepCopy(platDiscountFeeRates, new TypeReference<List<FeeRateDiscount>>() {});
   public static <T> T deepCopy(Object src, TypeReference<T> dstClazz) {if (null == src) {return null;}return JsonUtils.str2Obj(JsonUtils.obj2Str(src), dstClazz);}

总结一下

在不知所以然的时候很容易用错一些最基础的知识,越是基础的知识其发生错误的情况所导致的影响范围也越大,只有踏踏实实的自己尝试过,才知道框架怎么用最好,所以对于新知识最好不要抱有模糊的侥幸心理,这样其实自己心里也不踏实,不敢实践。Jackson是个好的开始,接下来则是Jooq以及Gradle。

相关文章:

【工作中问题解决实践 七】SpringBoot集成Jackson进行对象序列化和反序列化

去年10月份以来由于公司和家里的事情太多&#xff0c;所以一直没有学习&#xff0c;最近缓过来了&#xff0c;学习的脚步不能停滞啊。回归正题&#xff0c;其实前年在学习springMvc的时候也学习过Jackson【Spring MVC学习笔记 五】SpringMVC框架整合Jackson工具&#xff0c;但是…...

香港服务器遭受DDoS攻击后如何恢复运行?

​  您是否发现流量异常上升?您的网站突然崩溃了吗?当您注意到这些迹象时&#xff0c;可能是在陷入了DDoS攻击的困境&#xff0c;因而&#xff0c;当开始考虑使用香港服务器时&#xff0c;也应该考虑香港服务器设备受DDoS攻击时&#xff0c;如何从中恢复。 在 DDoS 攻击香港…...

【Hive】配置

目录 Hive参数配置方式 参数的配置方式 1. 文件配置 2. 命令行参数配置 3. 参数声明配置 配置源数据库 配置元数据到MySQL 查看MySQL中的元数据 Hive服务部署 hiveserver2服务 介绍 部署 启动 远程连接 1. 使用命令行客户端beeline进行远程访问 metastore服务 …...

IP-GUARD如何强制管控电脑设置开机密码要符合密码复杂度?

如何强制管控电脑设置开机密码要符合密码复杂度? 7 可以在控制台-【策略】-【定制配置】,添加一条配置,开启系统密码复杂度检测。 类别:自定义 关键字:bp_password_complexity 内容:1 效果图:...

剑指 Offer II 031. 最近最少使用缓存

题目链接 剑指 Offer II 031. 最近最少使用缓存 mid 题目描述 运用所掌握的数据结构&#xff0c;设计和实现一个 LRU(Least Recently Used&#xff0c;最近最少使用) 缓存机制 。 实现 LRUCache类&#xff1a; LRUCache(int capacity)以正整数作为容量 capacity初始化 LRU缓…...

44岁了,我从没想过在CSDN创作2年,会有这么大收获

1998年上的大学&#xff0c;02年毕业&#xff0c;就算从工作算起&#xff0c;我也有20余年的码龄生涯了。 但正式开启博文的写作&#xff0c;却是2021年开始的&#xff0c;差不多也就写了2年的博客&#xff0c;今天我来说说我在CSDN的感受和收获。 我是真的没想到&#xff0c;…...

相位相参信号源的设计--示波器上的信号不稳定,来回跑?

目录乱跑的波形边沿触发触发方式外部触发相参与非相参相位相参的射频信号源样机外观与内部设计软件设计上位机软件信号源使用方法PWM触发信号射频信号的时域波形射频信号的频谱输出功率在示波器的实际使用当中波形在示波器的时域上乱跑&#xff0c;左右移动&#xff0c;定不下来…...

Spring Boot 整合 RabbitMQ 多种消息模式

Spring Boot 整合 RabbitMQ 多种消息模式 准备工作集成 RabbitMQ发布/订阅模式点对点模式主题模式总结Spring Boot 是一个流行的 Java 应用程序开发框架,而 RabbitMQ 是一款可靠的消息队列软件。将 Spring Boot 和 RabbitMQ 结合起来可以帮助我们轻松地实现异步消息传递。Rabb…...

node多版本控制

前言 最近在折腾Python&#xff0c;并将node升级至v18.14.2。突然发现一个旧项目无法运行&#xff0c;也无法打包&#xff0c;里面的node-sass报错&#xff0c;显然这是因为node版本过高导致的。 将node版本降低至以前的v14.16.0&#xff0c;果然立马就能正常运行。 存在不同…...

Redis set集合

Redis set &#xff08;集合&#xff09;遵循无序排列的规则&#xff0c;集合中的每一个成员&#xff08;也就是元素&#xff0c;叫法不同而已&#xff09;都是字符串类型&#xff0c;并且不可重复。Redis set 是通过哈希映射表实现的&#xff0c;所以它的添加、删除、查找操作…...

漫画:什么是希尔排序算法?

希尔排序&#xff08;ShellSort&#xff09;是以它的发明者Donald Shell名字命名的&#xff0c;希尔排序是插入排序的改进版&#xff0c;实现简单&#xff0c;对于中等规模数据的性能表现还不错 一、排序思想 前情回顾&#xff1a;漫画&#xff1a;什么是插入排序算法&#xf…...

问卷工具选择要看哪些方面?

通常来讲&#xff0c;我们在使用一款问卷制作工具制作问卷时会有哪些需求呢&#xff1f; 一、用户需求 1、操作简单&#xff0c;易上手。 2、能够满足用户个性化的需求。 3、提供多语言服务。 4、能够帮助发布以及数据收集。 5、简化数据分析 市面上的问卷调查制作工具都…...

Qt之QPainter绘制多个矩形/圆形(含源码+注释)

一、绘制示例图 下图绘制的是矩形对象&#xff0c;但是将绘制矩形函数&#xff08;drawRect&#xff09;更改为绘制圆形&#xff08;drawEllipse&#xff09;即可绘制圆形。 二、思路解释 绘制矩形需要自然要获取矩形数据&#xff0c;因此通过鼠标事件获取每个矩形的rect数…...

介绍两款红队常用的信息收集组合工具

介绍两款红队常用的信息收集组合工具1.Ehole本地识别FOFA识别结果输出2.AlliN1.Ehole EHole(棱洞)3.0 红队重点攻击系统指纹探测工具 EHole是一款对资产中重点系统指纹识别的工具&#xff0c;在红队作战中&#xff0c;信息收集是必不可少的环节&#xff0c;如何才能从大量的资…...

类ChatGPT国产大模型ChatGLM-6B,单卡即可运行

2023年3月14日GPT4又发布了&#xff0c;在ChatGPT发展如火如荼的当下&#xff0c;我们更应该关注国内的进展&#xff0c;今天将分享一个清华大学基于GLM-130B模型开发的类似ChatGPT的ChatGLM-6B模型&#xff0c;ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0…...

vue的diff算法?

文章目录是什么比较方式原理分析Diff算法的步骤&#xff1a;首尾指针法比对顺序&#xff1a;是什么 diff 算法是一种通过同层的树节点进行比较的高效算法 其有两个特点&#xff1a; 比较只会在同层级进行, 不会跨层级比较 在diff比较的过程中&#xff0c;循环从两边向中间比较…...

C++ | 对比inline内联函数和宏的不同点

文章目录一、前言二、宏的优缺点分析1、概念回顾2、宏的缺点3、宏的优点三、inline内联函数1、概念2、特性①&#xff1a;空间换时间&#x1f381;趣味杂谈&#xff1a;庞大的游戏更新包3、特性②&#xff1a;inline实现机制4、特性③&#xff1a;inline的声明与定义反汇编观察…...

面试官问 : ArrayList 不是线程安全的,为什么 ?(看完这篇,以后反问面试官)

前言 金三银四 &#xff1f; 也许&#xff0c;但是。 近日&#xff0c;又收到金三银四一线作战小队成员反馈的战况 &#xff1a; 我不管你从哪里看的面经&#xff0c;但是我不允许你看到我这篇文章之后&#xff0c;还不清楚这个面试问题。 本篇内容预告&#xff1a; Array…...

Linux串口应用编程

一、 串口API 在Linux系统中,操作设备的统一接口就是:open/ioctl/read/write。 对于UART,又在ioctl之上封装了很多函数,主要是用来设置行规程。 所以对于UART,编程的套路就是: open设置行规程,比如波特率、数据位、停止位、检验位、RAW模式、一有数据就返回read/write 怎么设置…...

java程序员学前端-HTML篇

HTML 与 CSS HTML 是什么&#xff1a;即 HyperText Markup language 超文本标记语言&#xff0c;咱们熟知的网页就是用它编写的&#xff0c;HTML 的作用是定义网页的内容和结构。 HyperText 是指用超链接的方式组织网页&#xff0c;把网页联系起来Markup 是指用 <标签>…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...