diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts index 3b8da08..6670289 100644 --- a/docs/.vuepress/config.ts +++ b/docs/.vuepress/config.ts @@ -37,8 +37,9 @@ export default { {text: '业务功能设计',link:'/design/business/'}, ], }, - { text: '数据库', + { text: '数据库|ORM框架', children: [ + {text: 'Mybatis',link:'/database/mybatis/'}, {text: 'MySQL',link:'/database/mysql/'}, {text: 'NoSQL',link:'/database/nosql/'}, {text: 'PostgreSQL',link:'/database/postgresql/'}, @@ -54,6 +55,7 @@ export default { { text: '支付系统', link: '/pay/' }, { text: '工具集', children: [ + {text: 'Mac软件',link:'/tools/mac/'}, {text: 'Maven',link:'/tools/maven/'}, {text: 'Docker',link:'/tools/Docker/'}, {text: 'Git',link:'/tools/git/'}, diff --git "a/docs/database/mybatis/MyBatis\345\212\250\346\200\201SQL.md" "b/docs/database/mybatis/MyBatis\345\212\250\346\200\201SQL.md" new file mode 100644 index 0000000..5d15cd6 --- /dev/null +++ "b/docs/database/mybatis/MyBatis\345\212\250\346\200\201SQL.md" @@ -0,0 +1,41 @@ +# MyBatis动态SQL + +![640](./image/640.png) + +## foreach + +```xml + +``` + + + +## include + +引用其他mapepr + +```xml + ID,MAJOR,BIRTHDAY,AGE,NAME,HOBBY + +``` + +本mapper: + +```xml + + select * from student + + +``` + + + +参考: + +https://mp.weixin.qq.com/s/de55g6VPEU3_p8GvocXy3w + diff --git "a/docs/database/mybatis/MyBatis\345\270\270\347\224\250\346\241\206\346\236\266.md" "b/docs/database/mybatis/MyBatis\345\270\270\347\224\250\346\241\206\346\236\266.md" new file mode 100644 index 0000000..1dc9fcf --- /dev/null +++ "b/docs/database/mybatis/MyBatis\345\270\270\347\224\250\346\241\206\346\236\266.md" @@ -0,0 +1,11 @@ +# MyBatis常用框架 + +[MyBatis-Flex - MyBatis-Flex 官方网站](https://mybatis-flex.com/) + +[MyBatis-Plus (baomidou.com)](https://baomidou.com/) + +[mybatis-plus-ext: mybatis-plus框架的拓展包,在框架原有基础上做了进一步的轻度封装,增强内容:免手写Mapper、多数据源自动建表、数据自动填充、自动关联查询、冗余数据自动更新、动态查询条件等。 (gitee.com)](https://gitee.com/dromara/mybatis-plus-ext) + +[mybatis-mp: 基于mybatis封装的框架,满足绝大常用的CRUD,拥有复杂SQL的制作能力)](https://gitee.com/mybatis-mp/mybatis-mp) + +[AutoTable: 基于java实体上的注解完成数据库表自动维护的框架 (gitee.com)](https://gitee.com/tangzc/auto-table) diff --git "a/docs/database/mybatis/MyBatis\346\211\271\351\207\217\346\217\222\345\205\245.md" "b/docs/database/mybatis/MyBatis\346\211\271\351\207\217\346\217\222\345\205\245.md" new file mode 100644 index 0000000..4928429 --- /dev/null +++ "b/docs/database/mybatis/MyBatis\346\211\271\351\207\217\346\217\222\345\205\245.md" @@ -0,0 +1,57 @@ +# MyBatis 批量插入 + +1. for 循环批量插入 +2. 手动批量提交 +3. 集合方式批量新增 + +## for 循环批量插入 + +```xml + + + INSERT INTO XXXXXX (XXXXXX, XXXXXX) + VALUES(#{XXXXXX}, #{XXXXXX}) + + +``` + +```java + for(int i = 0 ;i < 10000; i++) { + Mapper.insert(XXXXXX); + } +``` + +耗时较高,不推荐 + +## 手动批量提交 + +```java +@Resource +private SqlSessionTemplate sqlSessionTemplate; +// 关闭自动提交 +SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false); + +for(int i = 0 ;i < 10000; i++) { + Mapper.insert(XXXXXX); + } + +sqlSession.commit(); +``` + +耗时较高,不推荐。 + +##集合方式批量新增 + +```xml + + + INSERT INTO XXXXXX (XXXXXX, XXXXXX) + VALUES + + (#{XXXXXX}, #{XXXXXX}) + + + +``` + +推荐使用。 \ No newline at end of file diff --git "a/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\346\217\222\344\273\266Interceptor.md" "b/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\346\217\222\344\273\266Interceptor.md" new file mode 100644 index 0000000..094551f --- /dev/null +++ "b/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\346\217\222\344\273\266Interceptor.md" @@ -0,0 +1,22 @@ +# MyBatis自定义插件Interceptor + +拦截器是一种基于 AOP(面向切面编程)的技术,它可以在目标对象的方法执行前后插入自定义的逻辑。MyBatis 定义了四种类型的拦截器,分别是: + +- Executor:拦截执行器的方法,例如 update、query、commit、rollback 等。可以用来实现缓存、事务、分页等功能。 +- ParameterHandler:拦截参数处理器的方法,例如 setParameters 等。可以用来转换或加密参数等功能。 +- ResultSetHandler:拦截结果集处理器的方法,例如 handleResultSets、handleOutputParameters 等。可以用来转换或过滤结果集等功能。 +- StatementHandler:拦截语句处理器的方法,例如 prepare、parameterize、batch、update、query 等。可以用来修改 SQL 语句、添加参数、记录日志等功能。 + +## 应用场景 + +- SQL 语句执行监控:可以拦截执行的 SQL 方法,打印执行的 SQL 语句、参数等信息,并且还能够记录执行的总耗时,可供后期的 SQL 分析时使用。 +- SQL 分页查询:MyBatis 中使用的 RowBounds 使用的内存分页,在分页前会查询所有符合条件的数据,在数据量大的情况下性能较差。通过拦截器,可以在查询前修改 SQL 语句,提前加上需要的分页参数。 +- 公共字段的赋值:在数据库中通常会有 createTime , updateTime 等公共字段,这类字段可以通过拦截统一对参数进行的赋值,从而省去手工通过 set 方法赋值的繁琐过程。 +- 数据权限过滤:在很多系统中,不同的用户可能拥有不同的数据访问权限,例如在多租户的系统中,要做到租户间的数据隔离,每个租户只能访问到自己的数据,通过拦截器改写 SQL 语句及参数,能够实现对数据的自动过滤。 +- SQL 语句替换:对 SQL 中条件或者特殊字符进行逻辑替换。 + + + +参考: + +https://mp.weixin.qq.com/s/ZBrTlHRx8Bseq7gLQeQ_Kw \ No newline at end of file diff --git "a/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\347\261\273\345\236\213\345\244\204\347\220\206\345\231\250TypeHandler.md" "b/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\347\261\273\345\236\213\345\244\204\347\220\206\345\231\250TypeHandler.md" new file mode 100644 index 0000000..d12851d --- /dev/null +++ "b/docs/database/mybatis/MyBatis\350\207\252\345\256\232\344\271\211\347\261\273\345\236\213\345\244\204\347\220\206\345\231\250TypeHandler.md" @@ -0,0 +1,84 @@ +# MyBatis自定义类型处理器TypeHandler + +![image-20240320092527345](./image/image-20240320092527345.png) + +```java +public interface TypeHandler { + + /** + * 设置 PreparedStatement 的指定参数。 + * + * @param ps PreparedStatement 对象。 + * @param index 参数在 PreparedStatement 中的位置。 + * @param parameter 要设置的参数值。 + * @param jdbcType JDBC 类型。这是一个可选参数,可以用来控制设置参数时的行为。 + * @throws SQLException 如果在设置参数时发生 SQL 异常。 + */ + void setParameter(PreparedStatement ps, int index, T parameter, JdbcType jdbcType) throws SQLException; + + /** + * 从 ResultSet 中获取数据并转换为 Java 类型。 + * + * @param rs ResultSet 对象。 + * @param columnName 要获取的数据的列名。 + * @return 转换后的 Java 类型数据。 + * @throws SQLException 如果在获取数据时发生 SQL 异常。 + */ + T getResult(ResultSet rs, String columnName) throws SQLException; + + /** + * 从 ResultSet 中获取数据并转换为 Java 类型。 + * + * @param rs ResultSet 对象。 + * @param columnIndex 要获取的数据的列索引。 + * @return 转换后的 Java 类型数据。 + * @throws SQLException 如果在获取数据时发生 SQL 异常。 + */ + T getResult(ResultSet rs, int columnIndex) throws SQLException; + + /** + * 从 CallableStatement 中获取数据并转换为 Java 类型。 + * + * @param cs CallableStatement 对象。 + * @param columnIndex 要获取的数据的列索引。 + * @return 转换后的 Java 类型数据。 + * @throws SQLException 如果在获取数据时发生 SQL 异常。 + */ + T getResult(CallableStatement cs, int columnIndex) throws SQLException; +} + +``` + +## 配置方式 + +1. 在Mapper.xml中声明(应用**单个**指定字段) + + ```xml + + + + ``` + +2. 在springboot的yml配置文件中设置类型处理器所在的**包名**,不是处理器路径(应用到**全局**) + + ```yml + mybatis-plus: + type-handlers-package: com.xxx.handler + ``` + +3. 实体类指定类型处理器。**必须在实体类上加`@TableName(autoResultMap = true)`,否则不生效** + + +```java +@Data +@Accessors(chain = true) +@TableName(autoResultMap = true) +public class User { +} +``` + + + +参考材料: + +https://juejin.cn/post/7320211683871801363?utm_source=gold_browser_extension diff --git "a/docs/database/mybatis/MybatisIDEA\346\217\222\344\273\266.md" "b/docs/database/mybatis/MybatisIDEA\346\217\222\344\273\266.md" new file mode 100644 index 0000000..3664831 --- /dev/null +++ "b/docs/database/mybatis/MybatisIDEA\346\217\222\344\273\266.md" @@ -0,0 +1,13 @@ +# Mybatis IDEA插件 + +MybatisCodeHelperPro:好用付费。 + +image-20240320091034331 + +MybatisX:免费 + +image-20240320091134884 + +Mybatis Log: + +image-20240320091301081 diff --git a/docs/database/mybatis/README.md b/docs/database/mybatis/README.md new file mode 100644 index 0000000..d73ac32 --- /dev/null +++ b/docs/database/mybatis/README.md @@ -0,0 +1,20 @@ +# Mybatis + +代码位置: + +[MyBatis常用框架](./MyBatis常用框架.md) + +[MybatisIDEA插件](./MybatisIDEA插件.md) + +[MyBatis自定义类型处理器TypeHandler](./MyBatis自定义类型处理器TypeHandler.md) + +[MyBatis自定义插件Interceptor](./MyBatis自定义插件Interceptor.md) + +MyBatis一级缓存、二级缓存 + +[MyBatis动态SQL](./MyBatis动态SQL.md) + +[MyBatis批量插入](./MyBatis批量插入.md) + +MyBatis设计模式 + diff --git a/docs/database/mybatis/image/640.png b/docs/database/mybatis/image/640.png new file mode 100644 index 0000000..78c91f6 Binary files /dev/null and b/docs/database/mybatis/image/640.png differ diff --git a/docs/database/mybatis/image/image-20240320091034331.png b/docs/database/mybatis/image/image-20240320091034331.png new file mode 100644 index 0000000..0a7f81a Binary files /dev/null and b/docs/database/mybatis/image/image-20240320091034331.png differ diff --git a/docs/database/mybatis/image/image-20240320091134884.png b/docs/database/mybatis/image/image-20240320091134884.png new file mode 100644 index 0000000..074c4e2 Binary files /dev/null and b/docs/database/mybatis/image/image-20240320091134884.png differ diff --git a/docs/database/mybatis/image/image-20240320091301081.png b/docs/database/mybatis/image/image-20240320091301081.png new file mode 100644 index 0000000..6266cc2 Binary files /dev/null and b/docs/database/mybatis/image/image-20240320091301081.png differ diff --git a/docs/database/mybatis/image/image-20240320092527345.png b/docs/database/mybatis/image/image-20240320092527345.png new file mode 100644 index 0000000..5a05905 Binary files /dev/null and b/docs/database/mybatis/image/image-20240320092527345.png differ diff --git a/docs/design/distributed/README.md b/docs/design/distributed/README.md index 4bc52f4..29be2f4 100644 --- a/docs/design/distributed/README.md +++ b/docs/design/distributed/README.md @@ -14,6 +14,8 @@ ## 分布式锁 +[Redis官方文档](./Redis官方文档.md) + [分布式锁概述](./分布式锁.md) [Redis分布式锁](./Redis分布式锁.md) diff --git "a/docs/design/distributed/Redis\345\256\230\346\226\271\346\226\207\346\241\243.md" "b/docs/design/distributed/Redis\345\256\230\346\226\271\346\226\207\346\241\243.md" new file mode 100644 index 0000000..137f55d --- /dev/null +++ "b/docs/design/distributed/Redis\345\256\230\346\226\271\346\226\207\346\241\243.md" @@ -0,0 +1,76 @@ +# Redis官方文档 + +[Distributed Locks with Redis | Redis](https://redis.io/docs/manual/patterns/distributed-locks/) + +## 分布式锁的设计原则 + +1. **互斥**(安全性):在任何给定时刻,只有一个客户端可以持有锁。 + +2. **无死锁**(有效性):超时机制,即使锁定资源的客户端崩溃或被分区,也总是可以获得锁; + +3. **容错性**(有效性):只要大多数 Redis 节点都启动,客户端就可以获取和释放锁。 +4. **同源性**:A加的锁,不能被B解锁 +5. **非阻塞**:获取不到锁,不能无限期等待; +6. **高性能**:加锁解锁是高性能的 + +## 锁定到单个实例 + +**加锁**: + +```lua +SET resource_name my_random_value NX PX 30000 +``` + +1. resource_name:本次业务有关的id。 +2. my_random_value:一串随机值,必须保证全局唯一。 +3. NX:当且仅当key不存在时,返回执行成功,否则执行失败。 +4. PX:30秒后,key将被自动删除。 + +执行命令后返回成功,表明服务成功的获得了锁。 + +**重试 + 重试间隔**: + +```java +while ((!result) && retryTimes-- > 0) { + +} +``` + +**解锁**:采用lua脚本 + +在删除key之前,一定要判断服务A持有的value与Redis内存储的value是否一致。如果贸然使用服务A持有的key来删除锁,则会误将服务B的锁释放掉。 + +```lua +if redis.call("get", KEYS[1])==ARGV[1] then + return redis.call("del", KEYS[1]) +else + return 0 +end +``` + +## 基于RedLock实现分布式锁 + +假设有两个服务A、B都希望获得锁,有一个包含了5个redis master的Redis Cluster,执行过程大致如下: + +1. 客户端获取当前时间戳,单位: 毫秒 +2. 服务A轮寻每个master节点,尝试创建锁。(这里锁的过期时间比较短,一般就几十毫秒) RedLock算法会尝试在大多数节点上分别创建锁,假如节点总数为n,那么大多数节点指的是n/2+1。 +3. 客户端计算成功建立完锁的时间,如果建锁时间小于超时时间,就可以判定锁创建成功。如果锁创建失败,则依次(遍历master节点)删除锁。 +4. 只要有其它服务创建过分布式锁,那么当前服务就必须轮寻尝试获取锁 + +## Redisson + +1. redisson所有指令都通过lua脚本执行,保证了操作的原子性 +2. redisson设置了watchdog看门狗,“看门狗”的逻辑保证了没有死锁发生 +3. redisson支持Redlock的实现方式。 + +执行流程: + +1. 线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。 +2. 线程去获取锁,获取失败: 订阅了解锁消息,然后再尝试获取锁,获取成功后,执行lua脚本,保存数据到redis数据库。 + + + +>参考文章 +> +>https://pdai.tech/md/arch/arch-z-lock.html + diff --git a/docs/tools/mac/README.md b/docs/tools/mac/README.md new file mode 100644 index 0000000..55ca07b --- /dev/null +++ b/docs/tools/mac/README.md @@ -0,0 +1,34 @@ +# Mac常用软件 + +别人整理的软件: + +https://github.com/jaywcjlove/awesome-mac/blob/master/README-zh.md + +## 已经安装的软件 + +RunCat + +文本: + +- WPS Office +- + +浏览器 + +- Microsoft Edge +- Google Chrome +- Safari浏览器 +- Firefox + +聊天: + +- 钉钉 +- 微信 + +音乐/视频: + +- QQ音乐 + +研发: + +- Visual Studio Code