MyBatis-Plus复习总结(一)

文章目录

  • 一、环境搭键
  • 二、基本CRUD
    • 2.1 BaseMapper
    • 2.2 插入
    • 2.3 删除
    • 2.4 修改
    • 2.5 查询
  • 三、通用Service
  • 四、常用注解
    • 4.1 雪花算法
    • 4.2 注解@TableLogic
  • 五、条件构造器和常用接口
    • 5.1 Wrapper介绍
    • 5.2 QueryWrapper
    • 5.3 UpdateWrapper
    • 5.4 condition
    • 5.5 LambdaQueryWrapper
    • 5.6 LambdaUpdateWrapper

一、环境搭键

这些配置可以当做模版,快速搭键MybatisPlus环境。

1、pom.xml:

	<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><lombok>1.18.20</lombok><druid>1.2.1</druid><pagehelper>1.4.1</pagehelper><mybatisPlus>3.5.1</mybatisPlus></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid}</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>${pagehelper}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatisPlus}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency></dependencies>

2、启动类:

@SpringBootApplication
@MapperScan("com.cabbage.mybatisplus.mapper")
public class MybatisplusStudyApplication {public static void main(String[] args) {SpringApplication.run(MybatisplusStudyApplication.class, args);}
}

3、创建实体类和mapper接口:

public interface UserMapper extends BaseMapper<User> {
}

在这里插入图片描述
4、配置数据库:

server:port: 8080
spring:profiles:active: devdatasource:druid:driver-class-name: ${sht.datasource.driver-class-name}url: jdbc:mysql://${sht.datasource.host}:${sht.datasource.port}/${sht.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=trueusername: ${sht.datasource.username}password: ${sht.datasource.password}
# 配置MyBatis日志
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
sht:datasource:driver-class-name: com.mysql.cj.jdbc.Driverhost: localhostport: 3306database: ssmusername: rootpassword: root

二、基本CRUD

2.1 BaseMapper

MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用,接口如下(具体内容可查看源码):

public interface BaseMapper<T> extends Mapper<T> {/*** 插入一条记录* @param entity 实体对象*/int insert(T entity);/*** 根据 ID 删除* @param id 主键ID*/int deleteById(Serializable id);/*** 根据实体(ID)删除* @param entity 实体对象* @since 3.4.4*/int deleteById(T entity);/*** 根据 columnMap 条件,删除记录* @param columnMap 表字段 map 对象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,删除记录* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

2.2 插入

	@Testvoid t2() {User user = new User(null, "one", 18, "one@qq.com");int res = userMapper.insert(user);log.info("影响的行数:{},user.id:{}", res, user.getId());//会默认基于雪花算法的策略生成id}

在这里插入图片描述


2.3 删除

    @Testvoid t3() {int res1 = userMapper.deleteById(1720674114752352257L);log.info("受影响的行数:{}",res1);List<User> list = Arrays.asList(new User(1L, null, null, null), new User(2L, null, null, null));int res2 = userMapper.deleteBatchIds(list);log.info("受影响的行数:{}",res2);}

在这里插入图片描述

    @Testvoid t4() {Map<String, Object> map = new HashMap<>();map.put("age", 28);map.put("name", "Tom");int res = userMapper.deleteByMap(map);log.info("受影响的行数:{}",res);}

在这里插入图片描述


2.4 修改

    @Testvoid t5() {int res = userMapper.updateById(new User(4L, "cabbage", 21, "cabbage@qq.com"));log.info("受影响的行数:{}",res);}

在这里插入图片描述


2.5 查询

    @Testvoid t6() {User user = userMapper.selectById(6L);log.info("user:{}", user);List<Long> list = Arrays.asList(5L, 6L);List<User> userList = userMapper.selectBatchIds(list);log.info("userList:{}",userList);}

在这里插入图片描述

    @Testvoid t7() {Map<String, Object> map = new HashMap<>();map.put("name", "one");map.put("age", 18);List<User> userList = userMapper.selectByMap(map);log.info("userList:{}", userList);}

在这里插入图片描述


三、通用Service

通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get查询单行remove删除list查询集合page分页save插入 前缀命名方式区分 Mapper 层避免混淆。

public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

在这里插入图片描述


测试查询记录数:

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@GetMappingpublic String test() {long count = userService.count();return String.valueOf(count);}
}

在这里插入图片描述

测试批量插入:

    @GetMappingpublic String test() {List<User> list = Arrays.asList(new User(7L, "two", 22, "two@qq.com"),new User(8L, "three", 25, "three@qq.com"));boolean res = userService.saveBatch(list);return String.valueOf(res);}

在这里插入图片描述

四、常用注解

可以看之前写过的文章,介绍的比较详细:https://cabbage.blog.csdn.net/article/details/123300666

4.1 雪花算法

背景:

需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。数据库的扩展方式主要包括:业务分库、主从复制,数据库分表。

数据库分表:

将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如,淘宝的几亿用户数据,如果全部存放在一台数据库服务器的一张表中,肯定是无法满足性能要求的,此时就需要对单表数据进行拆分。单表数据拆分有两种方式:垂直分表水平分表。示意图如下:

在这里插入图片描述


  • 垂直分表

垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。例如,前面示意图中的 nickname 和 description字段,假设我们是一个婚恋网站,用户在筛选其他用户的时候,主要是用 age 和 sex 两个字段进行查询,而 nickname 和description 两个字段主要用于展 示,一般不会在业务查询中用到。description本身又比较长,因此我们可以将这两个字段独立到另外一张表中,这样在查询 age 和 sex 时,就能带来一定的性能提升。

  • 水平分表

水平分表适合表行数特别大的表,有的公司要求单表行数超过 5000万就必须进行分表,这个数字可以作为参考,但并不是绝对标准,关键还是要看表的访问性能。对于一些比较复杂的表,可能超过1000万就要分表了;而对于一些简单的表,即使存储数据超过1亿行,也可以不分表。水平分表相比垂直分表,会引入更多的复杂性,例如要求全局唯一的数据id该如何处理。

方式一:主键自增

  • 以最常见的用户 ID 为例,可以按照1000000的范围大小进行分段,1 ~ 999999 放到表 1中,1000000 ~ 1999999 放到表2中,以此类推。
  • 复杂点:分段大小的选取。分段太小会导致切分后子表数量过多,增加维护复杂度;分段太大可能会导致单表依然存在性能问题,一般建议分段大小在 100 万至 2000 万之间,具体需要根据业务选取合适的分段大小。
  • 优点:可以随着数据的增加平滑地扩充新的表。例如,现在的用户是 100 万,如果增加到1000万,只需要增加新的表就可以了,原有的数据不需要动。
  • 缺点:分布不均匀。假如按照1000万来进行分表,有可能某个分段实际存储的数据量只有 1 条,而另外一个分段实际存储的数据量有1000万条。

方式二:取模

  • 同样以用户 ID 为例,假如我们一开始就规划了 10 个数据库表,可以简单地用 user_id % 10 的值来表示数据所属的数据库表编号,ID 为 985 的用户放到编号为 5 的子表中,ID 为 10086 的用户放到编号为 6 的子表中。
  • 复杂点:初始表数量的确定。表数量太多维护比较麻烦,表数量太少又可能导致单表性能存在问题。
  • 优点:表分布比较均匀。
  • 缺点:扩充新的表很麻烦,所有数据都要重分布。

方式三:雪花算法

  • 雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
  • 核心思想:
    长度共64bit(一个long型)。
    首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
    41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截)。
    10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
    12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。
  • 优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。

在这里插入图片描述


4.2 注解@TableLogic

再来看看逻辑删除的具体使用,数据库中is_delete默认值都是0,代表着未删除。

在这里插入图片描述

我们给数据库对应的实体类添加@TableLogic注解:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User implements Serializable {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;@TableLogic@TableField(value = "is_delete")private Integer isDelete;
}

执行删除代码:

    @Testvoid t1() {List<Long> list = Arrays.asList(4L, 5L);int res = userMapper.deleteBatchIds(list);log.info("共删除了{}条数据", res);}

通过控制台可以发现,执行删除语句,实际上是执行的修改操作。

在这里插入图片描述
数据库并未删除任何数据,只是把is_delete的值改为了1。

在这里插入图片描述


五、条件构造器和常用接口

5.1 Wrapper介绍

在这里插入图片描述

  • Wrapper :条件构造抽象类,最顶端父类
  • AbstractWrapper :用于查询条件封装,生成 sql 的 where 条件
  • QueryWrapper :查询条件封装
    UpdateWrapper :Update 条件封装
  • AbstractLambdaWrapper :使用Lambda 语法
  • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
    LambdaUpdateWrapper :Lambda 更新封装Wrapper

5.2 QueryWrapper

组装查询条件:

    @Testvoid t2() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("name", "t").between("age", 20, 30).isNotNull("email");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(user -> {log.info("查询到的结果是:{}", user);});}

从控制台可以看到,框架自动的为我们查询逻辑上存在的数据。

在这里插入图片描述
组装排序条件:

    @Testvoid t3() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("id");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(user -> {log.info("查询到的结果是:{}", user);});}

在这里插入图片描述

组装删除条件:

    @Testvoid t4() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");int res = userMapper.delete(queryWrapper);log.info("共删除了{}条数据", res);}

在这里插入图片描述
条件的优先级:

    @Testvoid t4() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//查询年龄大于20,并且名字中含有'o',或者邮箱是空的用户queryWrapper.gt("age", 20).like("name", "o").or().isNull("email");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(user -> {log.info("查询都的用户是:{}", user);});}

在这里插入图片描述


@Testvoid t4() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//查询名字中含有'o',并且年龄大于20或者邮箱是空的用户queryWrapper.like("name", 'o').and(i -> {i.gt("age", 20).or().isNull("email");});List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(user -> {log.info("查询都的用户是:{}", user);});}

在这里插入图片描述
组装select子句:

    @Testvoid t5() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("name", "age", "email").orderByAsc("age");List<Map<String, Object>> mapList = userMapper.selectMaps(queryWrapper);mapList.forEach(System.out::println);}

在这里插入图片描述

    @Testvoid t5() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("name", "age", "email").orderByAsc("age");List<User> userList = userMapper.selectList(queryWrapper);
//        List<Map<String, Object>> mapList = userMapper.selectMaps(queryWrapper);userList.forEach(System.out::println);}

在这里插入图片描述
实现子查询:

    @Testvoid t6() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.inSql("id", "select id from user where id > 6");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

在这里插入图片描述


5.3 UpdateWrapper

    @Testvoid t7() {//将(年龄大于25或邮箱为null)并且用户名中包含有t的用户信息修改UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.like("name", "t").and(i -> {i.gt("age", 25).or().isNull("email");});int res = userMapper.update(new User(9L, "five", 30, "five@qq.com"), updateWrapper);log.info("影响的结果是:{}", res);}

在这里插入图片描述


5.4 condition

在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因
此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若
没有选择则一定不能组装,以免影响SQL执行的结果

思路一:

	@Testvoid t8() {//定义查询条件,有可能为null(用户未输入或未选择)String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成if(StringUtils.isNotBlank(username)){queryWrapper.like("name","o");}if(ageBegin != null){queryWrapper.ge("age", ageBegin);}if(ageEnd != null){queryWrapper.le("age", ageEnd);}List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);}

在这里插入图片描述

思路二:

    @Testvoid t9() {String name = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(name), "name", "o").gt(ageBegin != null, "age", ageBegin).lt(ageEnd != null, "age", ageEnd);List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

思路二跟思路一的执行效果一样。


5.5 LambdaQueryWrapper

	@Testvoid t9() {String name = "o";Integer ageBegin = 10;Integer ageEnd = 30;LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(name), User::getName, "o").gt(ageBegin != null, User::getAge, ageBegin).lt(ageEnd != null, User::getAge, ageEnd);List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

在这里插入图片描述


5.6 LambdaUpdateWrapper

    @Testvoid t10() {LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "f").and(i -> i.gt(User::getAge, 24).or().isNull(User::getEmail));int result = userMapper.update(null, updateWrapper);System.out.println("受影响的行数:" + result);}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gradle中的依赖Dependencies说明与使用总结

【1】依赖的方式 Gradle 中的依赖分别为直接依赖&#xff0c;项目依赖&#xff0c;本地jar 依赖。 dependencies {//①.依赖当前项目下的某个模块[子工程]implementation project(:subject01)//②.直接依赖本地的某个jar文件implementation files(libs/foo.jar, libs/bar.jar…

行业安卓主板-基于RK3568/3288/3588的电子班牌/人脸识别门禁/室内对讲门禁方案解决方案(二)

电子班牌 智能电子班牌可在主页实时显示班级全面的基本信息&#xff0c;包括天气、班名、课程表、值日表等&#xff0c;并发布学校通知、班级通知。学生可刷卡自动登陆系统进行课堂反馈&#xff0c;教师和家长可及时了解教学反馈&#xff0c;打通学校、教师、学生之间的互动通…

Hive 解析 JSON 字符串数据的实现方式

文章目录 通过方法解析现实示例 通过序列化实现示例 通过方法解析现实 在 Hive 中提供了直接解析 JSON 字符串数据的方法 get_json_object(json_txt, path)&#xff0c;该方法参数解析如下&#xff1a; json_txt&#xff1a;顾名思义&#xff0c;就是 JSON 字符串&#xff1b;…

elasticsearch索引按日期拆分

1.索引拆分原因 如果单个索引数据量过大会导致搜索变慢&#xff0c;而且不方便清理历史数据。 例如日志数据每天量很大&#xff0c;而且需要定期清理以往日志数据。例如原索引为sc_all_system_log&#xff0c;现按天拆分索引sc_all_system_log20220902&#xff0c;sc_all_syste…

B-DS二叉树_输出所有目标路径

Description 给定二叉树和一个整数目标targetSum&#xff0c;输出所有从根结点到叶子结点的路径总和等于targetSun的路径。 Input 第一行输入t&#xff0c;表示有t个测试样例。 第二行起&#xff0c;每一行首先输入一个整数targetSum&#xff0c;接着输入n&#xff0c;接着输…

AMD老电脑超频及性能提升方案及实施

收拾电子元件的时候找到了若干古董的CPU 其中有一个X3 440 是原来同学主板烧了之后给我的&#xff0c;我从网上配了AM2 昂达主板&#xff0c;然后又买了AMD兼容内存&#xff0c;组成了win7 64位电脑&#xff0c;用起来非常不错&#xff0c;我把硬件配置和升级过程说明下&#x…

ELK极简上手

目录 引言 首先&#xff0c;下载相关的包 其次&#xff0c;安装启动elasticsearch 下一步&#xff0c;安装并启动logstash 最后&#xff0c;安装并启动kibana 进一步的&#xff0c;测试数据的流动 引言 最近整理电脑发现之前的一篇ELK极简入门笔记&#xff0c;现整理发出…

开发小程序需要多少钱?

随着移动互联网的快速发展&#xff0c;小程序已经成为了企业、个人创业者获取用户、提升品牌影响力的重要工具。然而&#xff0c;对于许多初次接触小程序的人来说&#xff0c;开发小程序需要多少钱&#xff0c;是他们最关心的问题。 首先我们需要明确的是&#xff0c;开发小程…

【漏洞复现】Drupal_小于7.32版本 _“Drupalgeddon” SQL注入漏洞(CVE-2014-3704)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 说明内容漏洞编号CVE-2014-3704漏洞名称Drupal “Drupalgeddon” SQL注入漏洞漏洞…

hackergame2023菜菜WP

文章目录 总结Hackergame2023更深更暗组委会模拟器猫咪小测标题HTTP集邮册Docker for everyone惜字如金 2.0Git? Git!高频率星球低带宽星球小型大语言模型星球旅行日记3.0JSON ⊂ YAML? 总结 最近看到科大在举办CTF比赛&#xff0c;刚好我学校也有可以参加&#xff0c;就玩了…

Lamport Clock算法

Lamport Clock 是一种表达逻辑时间的逻辑时钟&#xff08;logical clock&#xff09;&#xff0c;能够计算得到历史事件的时间偏序关系。 假设 P0进程是分布式集群中心节点中的监控者&#xff0c;用于统一管理分布式系统中事件的顺序。其他进程在发送消息之前和接受事件消息之后…

路由器基础(十二):IPSEC VPN配置

一、IPSec VPN基本知识 完整的IPSec协议由加密、摘要、对称密钥交换、安全协议四个部分组成。 两台路由器要建立IPSecVPN连接&#xff0c;就需要保证各自采用加密、摘要、对称密钥 交换、安全协议的参数一致。但是IPSec协议并没有确保这些参数一致的手段。 同时&#xff0c;IP…

Java 多线程的三大特性

在JAVA中&#xff0c;线程有原子性、可见性和有序性三大特性。 1.原子性 1.1 定义 对于涉及共享变量的操作&#xff0c;若该操作从其执行线程以外的任意线程来看都是不可分割的&#xff0c;那么我们就说该操作具有原子性。它包含以下两层含义&#xff1a; 访问&#xff08;读、…

【漏洞复现】Django_debug page_XSS漏洞(CVE-2017-12794)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证 说明内容漏洞编号CVE-2017-12794漏洞名称Django_debug page_XSS漏洞漏洞评级影响范…

与AI对话的艺术:如何优化Prompt以获得更好的响应反馈

前言 在当今数字化时代&#xff0c;人工智能系统已经成为我们生活的一部分。我们可以在智能助手、聊天机器人、搜索引擎等各种场合与AI进行对话。然而&#xff0c;要获得有益的回应&#xff0c;我们需要学会与AI进行有效的沟通&#xff0c;这就涉及到如何编写好的Prompt。 与…

开启AWS的ubuntu服务器的root用户登录权限

设置root用户密码 输入以下命令修改root用户密码 sudo passwd root输入以下命令切换到root用户 su root仅允许root用户用密码登录 输入以下命令编辑ssh配置文件 vi /etc/ssh/sshd_config新增以下配置允许root用户登录 PermitRootLogin yes把PasswordAuthentication修改为…

计算机网络第4章-IPv4

IPv4数据报格式 IPv4数据报格式如下图所示 其中&#xff0c;有如下的关键字段需要特别注意&#xff1a; 版本&#xff08;号&#xff09;&#xff1a; 版本字段共4比特&#xff0c;规定了数据报的IP协议版本。通过查看版本号吗&#xff0c;路由器能确定如何解释IP数据报的剩…

Python爬虫实战-批量爬取下载网易云音乐

大家好&#xff0c;我是python222小锋老师。前段时间卷了一套 Python3零基础7天入门实战https://blog.csdn.net/caoli201314/article/details/1328828131小时掌握Python操作Mysql数据库之pymysql模块技术https://blog.csdn.net/caoli201314/article/details/133199207一天掌握p…

MSF暴力破解SID和检测Oracle漏洞

暴力破解SID 当我们发现 Oracle 数据库的 1521 端口时,我们可能考虑使用爆破 SID(System Identifier)来进行进一步的探测和认证。在 Oracle 中,SID 是一个数据库的唯一标识符。当用户希望远程连接 Oracle 数据库时,需要了解以下几个要素:SID、用户名、密码以及服务器的 I…

深入理解WPF中的依赖注入和控制反转

在WPF开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff09;和控制反转&#xff08;Inversion of Control&#xff09;是程序解耦的关键&#xff0c;在当今软件工程中占有举足轻重的地位&#xff0c;两者之间有着密不可分的联系。今天就以一个简单的小例子&…