Mabitys总结
一、ORM
ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。
使用JDBC技术时,手动实现ORM映射:
使用ORM时,自动关系映射:
(1)ORM的具体实现可以认为是一个整体。
(2)SQL执行结果后,如果执行的是增删改,不需要去编写拆卸对象的代码,而是由ORM把对象中属性值取出放入到SQL中。
(3)SQL执行结果后,如果执行的是查询,会由ORM将数据库中查询到的结果,转换为对象。
(4)ORM技术相当于一个转换器,是面向对象语言和数据库之间的纽带。
(5)ORM框架封装了对象/关系的自动映射。
MyBatis:目前使用最多的ORM框架。
二、Mybatis中的SQL语句中的参数
1.MyBatis中最常用的占位符为 #{}。
1.SQL语句中使用#{}获取Test类中传递过来的参数值。
2. 当参数对象类型时,可以使用#{对象中属性名}获取对象属性值。
2.${} 的使用
${}在被MyBatis进行解析时,不会解析为占位符,而是直接解析成对应的值。也就是说使用${}时有点类似字符串拼接,会有SQL注入问题。 但是使用${}可以动态设置列名或表名。
3.#{}和${}的区别(经典面试题)
#{}被解析为?,用在设置列的值或条件值时,也可以使用在分页等需要设置具体值的情况。
${}表示字符串拼接,用在动态设置表名和动态设置列名的情况下。
三、MyBatis中DQL操作
yBatis的DQL操作在映射文件都是通过<select>
标签实现的。
SqlSession根据根据查询结果类型不同,提供了五种查询方法:
方法名 | 解释说明 |
---|---|
selectOne() | 查询一行数据时,返回值为Object。如果没有查询到,返回为nill,但是不能查询到多行。 |
selectMap() | 查询多行数据时,把其中某列结果当做key,每行结果为Value。 |
selectList() | 当查询多行数据时,返回值为List。如果没有查询到返回长度为零的List对象。 |
selectCursor() | 使用游标查询时使用,在大量数据时可以代替分页。 |
select() | 万能方法,需要自己定义结果处理器 |
四、SQL查询结果填充的几种方式(面试题)
1. 介绍
MyBatis会根据句映射关系把查询到的结果填充到指定结果集类型中。支持方式:
-
auto mapping:自动映射。当列名或列的别名与实体类属性名相同时不需要做额外配置。
-
resultMap:手动定义映射关系。
-
camel case:驼峰命名规则。
2. 驼峰转换
MyBatis提供了驼峰转换的能力。通过全局配置文件开启驼峰转换功能后,就可以让xxx_yyy自动映射到xxxYyy上。例如:列名叫做peo_id,可以自动映射到peoId的属性上。转换时去掉列中的下划线,把下划线后面单词首字母变大写。
五、接口绑定方案
MyBatis提供了一种接口绑定方案,通过SqlSession的getMapper方法产生接口的动态代理对象。然后通过对象调用接口中提供的功能。
1.接口绑定方案中映射文件的要求
在接口绑定方案中,对于映射文件有几点强制要求:
映射文件和接口需要在同一个包中
映射文件名称要和接口名称相同
namespace取值必须是接口的全限定路径
id属性值必须和方法名对应
resultType必须和方法返回值类型对应。如果方法返回值是集合类型,resultType中写泛型的类型
2.接口绑定方案下参数传递
接口中方法 | SqlSession的方法 |
---|---|
int insertPeople(People peo); | session.insert("insertPeople",peo); |
int deleteById(int id); | session.delete("deleteById",id); |
int updatePeople(People peo); | session.update("updatePeople",peo); |
People selectById(int id); | session.selectOne("selectById",id); |
List<People> selectAll(); | session.selectList("selectAll"); |
List<People> selectByUnameAndAddr(String name,String address); | session.selectList("selectByUnameAndAddr",Map类型参数) |
当方法带有多个参数将使用session.selectList("",Map类型参数)或session.selectOne("",Map类型参数)作为底层调用。
Mybatis会自动创建Map的key:
如果接口中方法没有使用注解定义名称,MyBatis使用内置名称作为key。
规则:arg0、arg1、argM(M为从0开始的数字,和方法参数顺序对应)或param1、param2、paramN(N为从1开始的数字,和方法参数顺序对应)。
也可以在接口方法参数中通过@Param("key名称")的形式进行定义key。一定使用了注解argN的这种形式就不能使用了,但是paramN的方式还是可以使用。
六、动态SQL
1. if标签
通过if处理用户多变的查询条件。类似于:
if(){} if(){}
<if>
标签的test属性值为OGNL(对象导航图语言)表达式,通过对象属性名可以快速获取到对象属性值。
2. choose
- choose标签相当于Java中的if...else if....else。
- 在choose标签里面可以有多个when标签和一个otherwise(可以省略)标签。
- 只要里面有一个when成立了后面的when和otherwise就不执行了。
3. trim标签
trim标签包含四个属性:
- prefix:子内容不是空字符串(""),就在子内容前面添加特定字符串。
- prefixOverrides:子内容是以某个内容开头,去掉这个内容。
- suffix:子内容不是空字符串(""),就在子内容后面添加特定字符串。
- suffixOverrides:子内容以某个内容结尾,就去掉这个内容。
trim只会对里面的子内容进行操作。如果子内容为空则不进行任何操作。后添加的内容会有空格。
特例:
如果内部字符串为要去掉的字符串,去掉后认为内容不为空,prefix依然添加。
4. where标签
where标签属于trim标签的简化版,被where标签包含的内容具备:
如果里面内容不为空串,在里面内容最前面添加where。
如果里面内容是以and开头,去掉最前面的and。
5. set标签
set标签是专门用在修改SQL中的,属于trim的简化版,带有下面功能:
如果子内容不为空串,在最前面添加set。
去掉最后一个逗号。
6. foreach标签
foreach标签表示循环,主要用在in查询或批量新增的情况。
foreach标签的属性解释说明:
- collection:要遍历的数组或集合对象。(如果参数没有使用@Param注解:arg0或array或list。. 如果使用@Param注解,使用注解的名称或param1。 )
- open:遍历结束在前面添加的字符串。
- close:遍历结束在后面添加的字符串。
- item:迭代变量。在foreach标签里面#{迭代变量}获取到循环过程中迭代变量的值。
- separator:分隔符。在每次循环中间添加的分割字符串。
- index:迭代的索引。从0开始的数字。
- nullable:是否允许数组或集合对象为null。如果设置为true,表示集合或数组允许为null。如果设置为false表示不允许数组或集合对象为null,一旦为null会出现异常。
7. bind标签(拼接使用)
bind标签表示对传递进来的参数重新赋值。最多的使用场景为模糊查询。通过bind可以不用在Java代码中对属性添加%。
8. sql和include标签
MyBatis的sql标签用于定义SQL片段,include标签用于引用sql标签定义的片段。
七、MyBatis中常用注解
八、多表查询(面试题)
1. 介绍
- 在学习MyBatis多表查询时其实就是在学习
<association>
标签和<collection>
标签。1.如果一个实体类关联另一个实体类的一个对象使用
<association>
。2.如果一个实体类关联一个实体类的List集合对象,需要使用
<collection>
。
- 这两个标签根据编写的SQL,分为N+1查询和联合查询两种方式。
2. 联合查询方式
<mapper namespace="com.bjsxt.mapper.EmpMapper"><!-- 每行数据最终返回的是Emp对象 --><resultMap id="empMap" type="Emp"><id column="e_id" property="id"/><result column="e_name" property="name"/><!-- 单个对象类型属性,使用association进行填充 --><!-- property:对象名 javaType:对象类型,支持别名--><association property="dept" javaType="Dept"><!-- 对属性对象里面的属性配置映射关系 --><id column="d_id" property="id"/><result column="d_name" property="name"/></association></resultMap><!-- 使用resultMap配置结果集映射 --><select id="seletAll" resultMap="empMap">select d_id,d_name,e_id,e_name,e_d_id from dept d,emp e where d.d_id=e.e_d_id</select>
</mapper>
3. N+1查询方式
N+1查询方式命名由来:当查询Emp表中N条数据时,需要编写1条查询全部的SQL和N条根据外键列值作为另一张表主键查询条件的N条SQL语句。
<resultMap id="deptMap2" type="Dept"><id column="d_id" property="id"></id><result column="d_name" property="name"></result>
</resultMap>
<select id="selectById" resultMap="deptMap2">select * from dept where d_id=#{id}
</select><resultMap id="empMap2" type="Emp"><id column="e_id" property="id"/><result column="e_name" property="name"/><!-- 此处依然使用association填充单个对象属性值.property和javaTye依然需要写 --><!-- select 调用另一个查询的路径,同一个映射文件中,前面namespace可以省略--><!-- column: 当前SQL查询结果哪个列值当做参数传递过去。如果是多个参数{"key":column,"key2":column2}--><association property="dept" javaType="Dept" select="com.bjsxt.mapper.DeptMapper.selectById" column="e_d_id"></association>
</resultMap><select id="selectAllN1" resultMap="empMap2">select e_id,e_name,e_d_id from emp
</select>
九、延迟加载(面试题)
延迟加载只能出现在多表联合查询的N+1方式中。表示当执行当前方法时,是否立即执行关联方法的SQL。
配置延迟加载:
全局配置。整个项目所有N+1位置都生效。
局部配置。只配置某个N+1位置。
两种方式需要选择其中一种,如果两种方式都使用了,局部配置方式生效。
1.全局配置方式
<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>
2.局部配置方式
局部配置方式需要在collection或association标签中配置fetchType属性。fetchType可取值:lazy(延迟加载)和earge(立即加载)。
当配置了fetchType属性后,全局settings的配置被覆盖,对于当前标签以fetchType属性值为准。
十、缓存(面试题)
1. 缓存介绍
MyBatis的缓存将相同查询条件的SQL语句执行一遍后所得到的结果存在内存或者某种缓存介质当中,当下次遇到一模一样的查询SQL时候不在执行SQL与数据库交互,而是直接从缓存中获取结果。
MyBatis分为一级缓存和二级缓存,同时也可配置关于缓存设置。
一级存储是SqlSession上的缓存。
二级缓存是在SqlSessionFactory(namespace)上的缓存。
默认情况下,MyBatis开启一级缓存,没有开启二级缓存。当数据量大的时候可以借助一些第三方缓存框架或Redis缓存来协助保存Mybatis的二级缓存数据。
2. 一级缓存
一级缓存想要生效,必须同时满足3个条件:
1. 同一个SqlSession对象。
2. 同一个select标签。本质为底层同一个JDBC的Statemen对象。
3. 完全相同的SQL,包含SQL的参数值也必须相同。
4. insert、delete、update操作会清空一级缓存数据。
5. close(),commit也会清空缓存。
2.1 一级缓存流程图
命中缓存:从Map中查询是否存在指定key。如果存在表示命中缓存,如果不存在这个key,需要访问数据库。
更新到缓存:把查询结果put到map中。
3. 二级缓存
3.1 二级缓存介绍
二级缓存是以namespace为标记的缓存,可能要借助磁盘,磁盘上的缓存,可以由一个SqlSessionFactory创建的SqlSession之间共享缓存数据,默认并不开启。
二级缓存生效条件:
同一个SqlSessionFactory对象。
同一个方法(<select>)。
SQL完全相同
重要提示:
二级缓存默认不开启,需要手动开启。只有当SqlSession执行commit或close时才会存储到二级缓存中。
3.2 配置二级缓存生效
1.全局开关:在mybatis.xml文件中的<settings>标签配置开启二级缓存。
<settings><setting name="cacheEnabled" value="true"/>
</settings>
2.分开关:在要开启二级缓存的mapper文件中开启缓存。使用<cache/>
配置时,注解的查询无法缓存。
-
<mapper namespace="com.bjsxt.mapper.EmpMapper"><cache/> </mapper>
3.二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口
public class Dept implements Serializable { }
4.重要总结
-
查询数据顺序 二级-->一级--->数据库--->把数据保存到一级 --->把数据保存到二级(临时),当sqlsession关闭或者提交的时候,把数据刷新到二级缓存(非临时)中。
-
执行了DML操作、close()、commit() ,会清空一级缓存,所以数据变更不可能到达二级缓存中。
十一、四大核心接口介绍及执行流程(面试题)
1. 四大核心接口介绍
-
Executor执行器,执行器负责整个SQL执行过程的总体控制。默认SimpleExecutor执行器。
-
StatementHandler语句处理器,语句处理器负责和JDBC层具体交互,包括prepare语句,执行语句,以及调用ParameterHandler.parameterize()。默认是PreparedStatementHandler。
-
ParameterHandler参数处理器,参数处理器,负责PreparedStatement入参的具体设置。默认使用DefaultParameterHandler。
-
ResultSetHandler结果集处理器,结果处理器负责将JDBC查询结果映射到java对象。默认使用DefaultResultSetHandler。
2. 执行顺序
(1)使用执行器Executor控制整个执行流程
(2)实例化StatementHandler,进行SQL预处理
(3)使用ParameterHandler设置参数
(4)使用StatementHandler执行SQL
(5)使用ResultSetHandler处理结果集
3.Executor执行器类型(面试题)
-
BaseExecutor:主要是使用了模板设计模式,共性被封装在 BaseExecutor 中,容易变化的内容被分离到了子类中 。
-
SimpleExecutor:默认的执行器类型。每次执行query和update(DML)都会重新创建Statement对象。
-
ReuseExecutor:执行器会重用预处理语句。不会每一次调用都去创建一个新的 Statement 对象,而是会重复利用以前创建好的(如果SQL相同的话)。
-
BatchExecutor:用在update(DML)操作中。所有SQL一次性提交。适用于批量操作。
-
-
CachingExecutor:处理缓存的执行器。无论使用上面三种执行器中的哪个。都是会执行CachingExecutor。
十二、MyBatis执行原理详解(较常见面试题)
- 首先加载全局配置文件为输入流,交给XPathParser解析器解析为Document文档对象,然后使用DOM解析Document文档对象,把解析结果存放在Configuration配置类中。
- 通过DefaultSqlSessionFactory实例化工厂,实例SqlSession的对象。创建了SqlSession接口的实现类DefaultSqlSession对象,在创建过程中,会同时创建Transaction事务对象、Executor执行器对象。如果当前项目有Interceptor拦截器,创建执行器时会执行拦截器。
- 通过JDK提供的Proxy创建接口的动态代理对象。
- 可以通过接口的代理对象调用方法。在调用方法时MyBatis会根据方法的类型判断调用SqlSession的哪个方法。例如:selectList、selectOne、update、insert等。
- 确定好具体调用SqlSession的哪个方法后,会按照执行器类型执行MyBatis四大核心接口,执行时也会触发拦截器Interceptor。最终会返回SQL的执行结果。
- 执行完方法后需要提交事务,提交时清空缓存、清除存储的Statement对象。
- 最后关闭SqlSession对象,释放资源。
相关文章:

Mabitys总结
一、ORM ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。 使用JDBC技术时,手动实现ORM映射: 使用ORM时,自动关系映射: &am…...

JAVA安全之Log4j-Jndi注入原理以及利用方式
什么是JNDI? JDNI(Java Naming and Directory Interface)是Java命名和目录接口,它提供了统一的访问命名和目录服务的API。 JDNI主要通过JNDI SPI(Service Provider Interface)规范来实现,该规…...

Spring源码系列-框架中的设计模式
简单工厂 实现方式: BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。 实质: 由一个工厂…...

数据的读取和保存-MATLAB
1 序言 在进行数据处理时,经常需要写代码对保存在文件中的数据进行读取→处理→保存的操作,流程图如下: 笔者每次在进行上述操作时,都需要百度如何“选中目标文件”以及如何“将处理好的数据保存到目标文件中”,对这一…...
C++ 输入、输出和整数运算
【问题描述】 编写一个程序,读入两个整数,计算并输出他们的和、积、商和余数。 【输入形式】 程序运行到输入时,不要显示输入提示信息。 输入为两个整数(在问题描述中记作A和B,程序中请自定变量名),A和B使…...
Element Plus 解决组件显示英文问题
要解决Element Plus日历组件显示英文的问题,可以使用Element Plus提供的国际化功能,切换成中文语言。下面是一个简单的示例: 首先,在main.ts或者你的入口文件中引入Element Plus的中文语言包和Vue I18n: import { cr…...

sqlite3.NotSupportedError: deterministic=True requires SQLite 3.8.3 or higher
问题描述 sqlite3.NotSupportedError: deterministicTrue requires SQLite 3.8.3 or higher 解决方法 A kind of solution is changing the database from sqlite3 to pysqlite3. After acticate the virtualenv, install pysqlite. pip3 install pysqlite3 pip3 install …...
单线程介绍、ECMAScript介绍、操作系统Windows、Linux 和 macOS
目录 单线程介绍ECMAScript介绍操作系统Windows、Linux 和 macOS 👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你的意见是我进步的财富! 单线程介绍 单线…...

【Docker】iptables基本原理
在当今数字化时代,网络安全问题变得越来越重要。为了保护我们的网络免受恶意攻击和未经授权的访问,我们需要使用一些工具来加强网络的安全性。其中,iptables是一个强大而受欢迎的防火墙工具,它可以帮助我们控制网络流量并保护网络…...

微服务架构——笔记(3)Eureka
微服务架构——笔记(3) 基于分布式的微服务架构 本次笔记为 此次项目的记录,便于整理思路,仅供参考,笔者也将会让程序更加完善 内容包括:1.支付模块、2.消费者订单模块、支付微服务入驻Eureka、Eureka集群…...

网络编程套接字(2)——简单的TCP网络程序
文章目录 一.简单的TCP网络程序1.服务端创建套接字2.服务端绑定3.服务端监听4.服务端获取连接5.服务端处理请求6.客户端创建套接字7.客户端连接服务器8.客户端发起请求9.服务器测试10.单执行流服务器的弊端 二.多进程版的TCP网络程序1.捕捉SIGCHLD信号2.让孙子进程提供服务 三.…...
MySQL数据库的简单的面试题
1、MySQL有哪些锁机制 MySQL有以下几种机制: 行级锁:行极锁在mysql 中最常用的锁机制,它只针对表的某一行进行加锁不受影响。MySQL的行级锁分为共享锁和排他锁两种类型,共享锁和排它锁不能同时存在于一行。 表级锁:表…...

hbuilderx打包应用上传到app store构建版本的教程
简介: 将ipa上架app store的过程中,发现需要将打包的ipa文件上传到app store的构建版本里,但是苹果官方推荐的上传工具,只有xcode和transporter等工具,这些工具是不能安装在windows电脑的。那么有没有windows电脑的上传…...

第五届泰迪杯数据分析技能赛B题源码图片分享
需要B题源码以及第六届带队”指导“请私信本人,团队包含技能赛双一等,数学建模省一,泰迪杯挖掘国一,研究生队友。 去年一等作品可视化图如下,私信获取源码...

【小白专用】VSCode下载和安装与配置PHP开发环境(详细版) 23.11.08
1. 下载VSCode2. 解决VSCode下载速度特别慢3. 安装VSCode 一、VSCode介绍 VSCode 是一款由微软开发且跨平台的免费源代码编辑器;该软件支持语法高亮、代码自动补全、代码重构、查看定义功能,并且内置了命令行工具和 Git 版本控制系统。 二、官方下载地址…...

Qlik Sense : Fetching data with Qlik Web Connectors
目录 Connecting to data sources Opening a connector Connecting to a data source Authenticating the connector Defining table parameters Using standard mode or legacy mode Standard mode Connector overview Using multi-line input parameters to fetch da…...

聊一聊 tcp/ip 在.NET故障分析的重要性
一:背景 1. 讲故事 这段时间分析了几个和网络故障有关的.NET程序之后,真的越来越体会到计算机基础课的重要,比如 计算机网络 课,如果没有对 tcpip协议 的深刻理解,解决这些问题真的很难,因为你只能在高层做…...

利用梯度上升可视化卷积核:基于torch实现
利用梯度上升可视化卷积核 文章目录 前言基本原理版本和包结果展示 简单绘图修改源码绘图方法一 方法二(推荐) 报错解决总结 前言 基于梯度上升的可视化是一种常用的技术,用于理解卷积神经网络(CNN)中的卷积核是如何对…...
python+playwright 学习-85 启动参数 proxy 设置代理几种方式
前言 在使用playwright执行代码的时候,如需设置代理,可以在启动的时候加proxy 参数设置代理。 本篇总结下可以加proxy代理的几种方式。 launch 启动全局代理 launch 启动的时候设置全局代理,以下是示例 from playwright.sync_api import Playwright, sync_playwrightwit…...
Clion 搭建Qt projects
Qt projects Qt is a cross-platform C framework for creating GUI applications. Qt uses its own build system, qmake, and also supports building with CMake starting from the version Qt4. Qt是一款创建桌面程序的跨平台的C框架。qmake是Qt自有的构建系统࿰…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...