一,什么情况下需要使用多个redis数据源?

为了缓存数据,通常我们会在线上使用多个redis的cluster,

每个cluster中缓存不同的数据,以方便管理.

例如:我们缓存了杂志文章/商品信息/分类页面

同时我们又使用一个redis cluster作为分布式session

这里就会有多个redis数据源在项目中

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

对应的源码可以访问这里获取: https://github.com/liuhongdi/

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,演示项目说明:

1,项目地址:

  1. https://github.com/liuhongdi/multiredissource

2, 项目原理

存储session使用redis集群,

另外使用两个redis实例做缓存

关于redis集群的搭建请参见:

  1. https://www.cnblogs.com/architectforest/p/13196749.html

3, 项目结构:

如图:

三,项目配置文件说明:

application.properties

  1. #default redis,for session
    spring.redis.cluster.nodes=172.17.0.2:6379,172.17.0.3:6379,172.17.0.4:6379,172.17.0.5:6379,172.17.0.6:6379,172.17.0.7:6379
  2. spring.redis.cluster.max-redirects=3
  3. spring.redis.password=lhddemo
  4. spring.redis.database=0
  5. spring.session.store-type=redis
  6. spring.redis.lettuce.pool.max-active=8
  7. spring.redis.lettuce.pool.max-wait=1
  8. spring.redis.lettuce.pool.max-idle=8
  9. spring.redis.lettuce.pool.min-idle=0
  10.  
  11. #redis1
  12. spring.redis1.host=127.0.0.1
  13. spring.redis1.port=6379
  14. spring.redis1.password=lhddemo
  15. spring.redis1.database=0
  16. spring.redis1.lettuce.pool.max-active=8
  17. spring.redis1.lettuce.pool.max-wait=1
  18. spring.redis1.lettuce.pool.max-idle=8
  19. spring.redis1.lettuce.pool.min-idle=0
  20.  
  21. #redis2
  22. spring.redis2.host=127.0.0.1
  23. spring.redis2.port=6380
  24. spring.redis2.password=lhddemo
  25. spring.redis2.database=0
  26. spring.redis2.lettuce.pool.max-active=8
  27. spring.redis2.lettuce.pool.max-wait=1
  28. spring.redis2.lettuce.pool.max-idle=8
  29. spring.redis2.lettuce.pool.min-idle=0

说明:共3个redis,

存储session的集群有6个节点(3主3从):

172.17.0.2:6379,

172.17.0.3:6379,

172.17.0.4:6379,

172.17.0.5:6379,

172.17.0.6:6379,

172.17.0.7:6379

redis1是非集群结点:

127.0.0.1:6379

redis2是非集群结点:

127.0.0.1:6380

四,java代码说明

1,RedisConfig.java

  1. @Configuration
  2. public class RedisConfig {
  3. @Bean
  4. @Primary
  5. public LettuceConnectionFactory redissessionLettuceConnectionFactory(RedisClusterConfiguration redisSessionRedisConfig,
  6. GenericObjectPoolConfig redisSessionPoolConfig) {
  7. LettuceClientConfiguration clientConfig =
  8. LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
  9. .poolConfig(redisSessionPoolConfig).build();
  10. return new LettuceConnectionFactory(redisSessionRedisConfig, clientConfig);
  11. }
  12.  
  13. @Bean
  14. public RedisTemplate<String, String> redisSessionTemplate(
  15. @Qualifier("redissessionLettuceConnectionFactory") LettuceConnectionFactory redissessionLettuceConnectionFactory) {
  16. RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
  17. redisTemplate.setKeySerializer(new StringRedisSerializer());
  18. redisTemplate.setValueSerializer(new StringRedisSerializer());
  19. //使用StringRedisSerializer来序列化和反序列化redis的ke
  20. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  21. redisTemplate.setHashValueSerializer(new StringRedisSerializer());
  22. //开启事务
  23. redisTemplate.setEnableTransactionSupport(true);
  24. redisTemplate.setConnectionFactory(redissessionLettuceConnectionFactory);
  25. redisTemplate.afterPropertiesSet();
  26. return redisTemplate;
  27. }
  28.  
  29. @Bean
  30. @ConditionalOnBean(name = "redis1RedisConfig")
  31. public LettuceConnectionFactory redis1LettuceConnectionFactory(RedisStandaloneConfiguration redis1RedisConfig,
  32. GenericObjectPoolConfig redis1PoolConfig) {
  33. LettuceClientConfiguration clientConfig =
  34. LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
  35. .poolConfig(redis1PoolConfig).build();
  36. return new LettuceConnectionFactory(redis1RedisConfig, clientConfig);
  37. }
  38.  
  39. @Bean
  40. public RedisTemplate<String, String> redis1Template(
  41. @Qualifier("redis1LettuceConnectionFactory") LettuceConnectionFactory redis1LettuceConnectionFactory) {
  42. RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
  43. redisTemplate.setKeySerializer(new StringRedisSerializer());
  44. redisTemplate.setValueSerializer(new StringRedisSerializer());
  45. //使用StringRedisSerializer来序列化和反序列化redis的ke
  46. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  47. redisTemplate.setHashValueSerializer(new StringRedisSerializer());
  48. //开启事务
  49. redisTemplate.setEnableTransactionSupport(true);
  50. redisTemplate.setConnectionFactory(redis1LettuceConnectionFactory);
  51. redisTemplate.afterPropertiesSet();
  52.  
  53. return redisTemplate;
  54. }
  55.  
  56. @Bean
  57. @ConditionalOnBean(name = "redis2RedisConfig")
  58. public LettuceConnectionFactory redis2LettuceConnectionFactory(RedisStandaloneConfiguration redis2RedisConfig,
  59. GenericObjectPoolConfig redis2PoolConfig) {
  60. LettuceClientConfiguration clientConfig =
  61. LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(100))
  62. .poolConfig(redis2PoolConfig).build();
  63. return new LettuceConnectionFactory(redis2RedisConfig, clientConfig);
  64. }
  65.  
  66. @Bean
  67. @ConditionalOnBean(name = "redis2LettuceConnectionFactory")
  68. public RedisTemplate<String, String> redis2Template(
  69. @Qualifier("redis2LettuceConnectionFactory") LettuceConnectionFactory redis2LettuceConnectionFactory) {
  70. RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
  71. redisTemplate.setValueSerializer(new StringRedisSerializer());
  72. redisTemplate.setHashValueSerializer(new StringRedisSerializer());
  73. //使用StringRedisSerializer来序列化和反序列化redis的ke
  74. redisTemplate.setKeySerializer(new StringRedisSerializer());
  75. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  76. //开启事务
  77. redisTemplate.setEnableTransactionSupport(true);
  78. redisTemplate.setConnectionFactory(redis2LettuceConnectionFactory);
  79. redisTemplate.afterPropertiesSet();
  80. return redisTemplate;
  81. }
  82.  
  83. @Configuration
  84. public static class RedisSessionConfig {
  85. @Value("${spring.redis.cluster.nodes}")
  86. private String nodes;
  87. @Value("${spring.redis.cluster.max-redirects}")
  88. private Integer maxRedirects;
  89. @Value("${spring.redis.password}")
  90. private String password;
  91. @Value("${spring.redis.database}")
  92. private Integer database;
  93.  
  94. @Value("${spring.redis.lettuce.pool.max-active}")
  95. private Integer maxActive;
  96. @Value("${spring.redis.lettuce.pool.max-idle}")
  97. private Integer maxIdle;
  98. @Value("${spring.redis.lettuce.pool.max-wait}")
  99. private Long maxWait;
  100. @Value("${spring.redis.lettuce.pool.min-idle}")
  101. private Integer minIdle;
  102.  
  103. @Bean
  104. public GenericObjectPoolConfig redisSessionPoolConfig() {
  105. GenericObjectPoolConfig config = new GenericObjectPoolConfig();
  106. config.setMaxTotal(maxActive);
  107. config.setMaxIdle(maxIdle);
  108. config.setMinIdle(minIdle);
  109. config.setMaxWaitMillis(maxWait);
  110. return config;
  111. }
  112.  
  113. @Bean
  114. public RedisClusterConfiguration redisSessionRedisConfig() {
  115. RedisClusterConfiguration config = new RedisClusterConfiguration();
  116. String[] sub = nodes.split(",");
  117. List<RedisNode> nodeList = new ArrayList<>(sub.length);
  118. String[] tmp;
  119. for (String s : sub) {
  120. tmp = s.split(":");
  121. nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
  122. }
  123. config.setClusterNodes(nodeList);
  124. config.setMaxRedirects(maxRedirects);
  125. config.setPassword(RedisPassword.of(password));
  126. return config;
  127. }
  128. }
  129.  
  130. @Configuration
  131. public static class Redis1Config {
  132. @Value("${spring.redis1.host}")
  133. private String host;
  134. @Value("${spring.redis1.port}")
  135. private Integer port;
  136. @Value("${spring.redis1.password}")
  137. private String password;
  138. @Value("${spring.redis1.database}")
  139. private Integer database;
  140. @Value("${spring.redis1.lettuce.pool.max-active}")
  141. private Integer maxActive;
  142. @Value("${spring.redis1.lettuce.pool.max-idle}")
  143. private Integer maxIdle;
  144. @Value("${spring.redis1.lettuce.pool.max-wait}")
  145. private Long maxWait;
  146. @Value("${spring.redis1.lettuce.pool.min-idle}")
  147. private Integer minIdle;
  148.  
  149. @Bean
  150. public GenericObjectPoolConfig redis1PoolConfig() {
  151. GenericObjectPoolConfig config = new GenericObjectPoolConfig();
  152. config.setMaxTotal(maxActive);
  153. config.setMaxIdle(maxIdle);
  154. config.setMinIdle(minIdle);
  155. config.setMaxWaitMillis(maxWait);
  156. return config;
  157. }
  158.  
  159. @Bean
  160. public RedisStandaloneConfiguration redis1RedisConfig() {
  161. RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
  162. config.setHostName(host);
  163. config.setPassword(RedisPassword.of(password));
  164. config.setPort(port);
  165. config.setDatabase(database);
  166. return config;
  167. }
  168. }
  169.  
  170. @Configuration
  171. @ConditionalOnProperty(name = "host", prefix = "spring.redis2")
  172. public static class Redis2Config {
  173. @Value("${spring.redis2.host}")
  174. private String host;
  175. @Value("${spring.redis2.port}")
  176. private Integer port;
  177. @Value("${spring.redis2.password}")
  178. private String password;
  179. @Value("${spring.redis2.database}")
  180. private Integer database;
  181.  
  182. @Value("${spring.redis2.lettuce.pool.max-active}")
  183. private Integer maxActive;
  184. @Value("${spring.redis2.lettuce.pool.max-idle}")
  185. private Integer maxIdle;
  186. @Value("${spring.redis2.lettuce.pool.max-wait}")
  187. private Long maxWait;
  188. @Value("${spring.redis2.lettuce.pool.min-idle}")
  189. private Integer minIdle;
  190.  
  191. @Bean
  192. public GenericObjectPoolConfig redis2PoolConfig() {
  193. GenericObjectPoolConfig config = new GenericObjectPoolConfig();
  194. config.setMaxTotal(maxActive);
  195. config.setMaxIdle(maxIdle);
  196. config.setMinIdle(minIdle);
  197. config.setMaxWaitMillis(maxWait);
  198. return config;
  199. }
  200.  
  201. @Bean
  202. public RedisStandaloneConfiguration redis2RedisConfig() {
  203. RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
  204. config.setHostName(host);
  205. config.setPassword(RedisPassword.of(password));
  206. config.setPort(port);
  207. config.setDatabase(database);
  208. return config;
  209. }
  210. }
  211. }

说明:

分别构造了三个redisTemplate:

redisSessionTemplate:访问redis session cluster

redis1Template:访问redis1

redis2Template:访问redis2

因为要供session默认使用,
所以给第一个LettuceConnectionFactory加上@Primary注解

cluster的配置要使用RedisClusterConfiguration类,

注意与:RedisStandaloneConfiguration区分

2,CacheController.java

  1. @RestController
  2. @RequestMapping("/cache")
  3. public class CacheController {
  4.  
  5. @Resource
  6. RedisTemplate<String, String> redis1Template;
  7. @Resource
  8. RedisTemplate<String, String> redis2Template;
  9.  
  10. /*
  11. * get redis1 cache
  12. */
  13. @RequestMapping("/redis1get")
  14. public String redis1Get(HttpServletRequest request){
  15. String goodsname = redis1Template.opsForValue().get("goodsname1");
  16. return goodsname;
  17. }
  18.  
  19. /*
  20. * write redis1 cache
  21. */
  22. @RequestMapping("/redis1set/{name}")
  23. public String redis1Set(@PathVariable String name) {
  24. //request.getSession().setAttribute("goods", name);
  25. redis1Template.opsForValue().set("goodsname1",name);
  26. return "ok";
  27. }
  28.  
  29. /*
  30. * get redis2 cache
  31. * */
  32. @RequestMapping("/redis2get")
  33. public String redis2Get(HttpServletRequest request){
  34. String goodsname2 = redis2Template.opsForValue().get("goodsname2");
  35. return goodsname2;
  36. }
  37.  
  38. /*
  39. * write redis2 cache
  40. * */
  41. @RequestMapping("/redis2set/{name}")
  42. public String redis2Set(@PathVariable String name) {
  43. //request.getSession().setAttribute("goods", name);
  44. redis2Template.opsForValue().set("goodsname2",name);
  45. return "ok";
  46. }
  47. }

说明:对redis1和redis2分别读取和写入

3,SessionController.java

  1. @RestController
  2. @RequestMapping("/session")
  3. public class SessionController {
  4. /*
  5. * read session
  6. * */
  7. @RequestMapping("/get")
  8. public Object getSession(HttpServletRequest request){
  9.  
  10. Map<String, Object> map = new HashMap<>();
  11. map.put("sessionId", request.getSession().getId());
  12. map.put("user", request.getSession().getAttribute("user"));
  13. map.put("maxInactiveInterval", request.getSession().getMaxInactiveInterval());
  14. //map.put("ttl", request.getSession().);
  15. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  16. String time = sdf.format(new Date(request.getSession().getCreationTime()));
  17. map.put("creationTime", time);
  18. return map;
  19. }
  20.  
  21. /*
  22. * write session
  23. * */
  24. @RequestMapping("/set/{name}")
  25. public String setSession(@PathVariable String name, HttpServletRequest request) {
  26. request.getSession().setAttribute("user", name);
  27. return "ok";
  28. }
  29. }

说明:对session的读取和写入

五,多redis数据源效果测试

1,查看三个redis的数据:

redissession

  1. [root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
  2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
  3. >>> Calling keys *
  4. 172.17.0.2:6379:
  5. 172.17.0.4:6379:
  6. 172.17.0.3:6379:
  7. 172.17.0.6:6379:
  8. 172.17.0.7:6379:
  9. 172.17.0.5:6379:

redis1:

  1. 127.0.0.1:6379> keys *
  2. (empty list or set)

redis2:

  1. 127.0.0.1:6380> keys *
  2. (empty list or set)

2,测试session:

访问:http://127.0.0.1:8080/session/set/thislaoliu

设置一个session值为thislaoliu:

访问:http://127.0.0.1:8080/session/get

查询我们设置的session值是否生效?

从redis的控制台检查写入情况:

  1. [root@redis4 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -a lhddemo -c --cluster call 172.17.0.2:6379 keys \*
  2. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
  3. >>> Calling keys *
  4. 172.17.0.2:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
  5. 172.17.0.4:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
  6. 172.17.0.3:6379: spring:session:expirations:1593321720000
  7. 172.17.0.6:6379: spring:session:sessions:expires:97a889f8-7122-4248-a5fc-4e559cb429e5
  8. 172.17.0.7:6379: spring:session:expirations:1593321720000
  9. 172.17.0.5:6379: spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5

我们连接到172.17.0.4,查询session的值:

  1. [root@redis3 /]# /usr/local/soft/redis-6.0.5/bin/redis-cli -c -h 172.17.0.4

看session的内容:

  1. 172.17.0.4:6379> hgetall spring:session:sessions:97a889f8-7122-4248-a5fc-4e559cb429e5
  2. 1) "sessionAttr:user"
  3. 2) "\xac\xed\x00\x05t\x00\nthislaoliu"
  4. 3) "creationTime"
  5. 4) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9CW\xb7"
  6. 5) "maxInactiveInterval"
  7. 6) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
  8. 7) "lastAccessedTime"
  9. 8) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01r\xf9D)n"

可以看到user的值是我们所设置的:thislaoliu

3,测试redis1

访问:http://127.0.0.1:8080/cache/redis1set/cup1

设置一个key,值为:cup1

访问:http://127.0.0.1:8080/cache/redis1get

返回我们设置的值:

连接到redis控制台:

  1. [liuhongdi@localhost ~]$ /usr/local/soft/redis/bin/redis-cli

从redis控制台查看kv

  1. 127.0.0.1:6379> get goodsname1
  2. "cup1"

4,测试redis2

访问:http://127.0.0.1:8080/cache/redis2set/phone1

设置一个key,值为:phone1

访问:http://127.0.0.1:8080/cache/redis2get

返回我们设置的值:

连接到redis控制台

  1. [root@localhost etc]# /usr/local/soft/redis/bin/redis-cli -p 6380

从控制台查看值

  1. 127.0.0.1:6380> get goodsname2
  2. "phone1"

六,查看spring boot的版本

  1. . ____ _ __ _ _
  2. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
  3. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
  4. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
  5. ' |____| .__|_| |_|_| |_\__, | / / / /
  6. =========|_|==============|___/=/_/_/_/
  7. :: Spring Boot :: (v2.3.1.RELEASE)

spring boot:使用多个redis数据源(spring boot 2.3.1)的更多相关文章

  1. Spring boot配置多个Redis数据源操作实例

    原文:https://www.jianshu.com/p/c79b65b253fa Spring boot配置多个Redis数据源操作实例 在SpringBoot是项目中整合了两个Redis的操作实例 ...

  2. Spring Boot 集成Mybatis实现多数据源

    静态的方式 我们以两套配置方式为例,在项目中有两套配置文件,两套mapper,两套SqlSessionFactory,各自处理各自的业务,这个两套mapper都可以进行增删改查的操作,在这两个主MYS ...

  3. spring boot 基础篇 -- 阿里多数据源

    这块是比较基础的配置,阿里数据库配置还是比较好用的,并且可以用来监控数据源的情况.废话不多说,下面看代码. 基于maven项目,在pom.xml中添加引用: <dependency> &l ...

  4. Spring Boot WebFlux-06——WebFlux 整合 Redis

    第06课:WebFlux 整合 Redis 前言 上一篇内容讲了如何整合 MongoDB,这里继续讲如何操作 Redis 这个数据源,那什么是 Reids? Redis 是一个高性能的 key-val ...

  5. Spring Boot 学习笔记--整合Redis

    1.新建Spring Boot项目 添加spring-boot-starter-data-redis依赖 <dependency> <groupId>org.springfra ...

  6. spring boot 中 Mybatis plus 多数据源的配置方法

    最近在学习spring boot,发现在jar包依赖方面做很少的工作量就可以了,对于数据库操作,我用的比较多的是mybatis plus,在中央仓库已经有mybatis-plus的插件了,对于单数据源 ...

  7. Spring Boot 2.x整合Redis

    最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...

  8. Spring Boot HikariCP 一 ——集成多数据源

    其实这里介绍的东西主要是参考的另外一篇文章,数据库读写分离的. 参考文章就把链接贴出来,里面有那位的代码,简单明了https://gitee.com/comven/dynamic-datasource ...

  9. Spring Boot + Mybatis多数据源和动态数据源配置

    文章转自 https://blog.csdn.net/neosmith/article/details/61202084 网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种 ...

随机推荐

  1. adb安装apk包提示protocol failure问题

    截图来自CSDN,待验证

  2. 吴恩达《深度学习》-第一门课 (Neural Networks and Deep Learning)-第三周:浅层神经网络(Shallow neural networks) -课程笔记

    第三周:浅层神经网络(Shallow neural networks) 3.1 神经网络概述(Neural Network Overview) 使用符号$ ^{[

  3. Linux 获取屏幕分辨率与窗口行列数(c/c++)

    获取当前分辨率 #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<s ...

  4. 小BUG大原理 | 第一篇:重写WebMvcConfigurationSupport后SpringBoot自动配置失效

    一.背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错.正常情况下看起来应该是个小BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动.因为这个看似小BUG我了解到不少未知的 ...

  5. Gradle系列之Android Gradle基础配置

    原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...

  6. 软件工程与UML作业3(互评作业)

    博客班级 https://edu.cnblogs.com/campus/fzzcxy/2018SE1/ 作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018S ...

  7. python中的画笔控制函数

    蟒蛇绘制代码中的画笔控制函数 penup() ,pendown() ,pensize() , pencolor()函数 这里就将海龟想象成画笔 画笔控制函数,画笔操作后一直有效,一般成对出现 将画笔抬 ...

  8. 口罩预约管理系统——系统网站实现(前端+PHP+MySQL)

    口罩预约管理系统网站实现 一.前言 二.系统登陆逻辑及界面实现 三.用户模块 1.用户预约系统界面 2.用户查看我的订单界面 3.用户修改预约信息 四.管理员模块 1.管理员登陆界面 2.查看用户预约 ...

  9. 浅谈 ArrayList 及其扩容机制

    浅谈ArrayList ArrayList类又称动态数组,同时实现了Collection和List接口,其内部数据结构由数组实现,因此可对容器内元素实现快速随机访问.但因为ArrayList中插入或删 ...

  10. Spring AOP系列(一)— 代理模式

    Spring AOP系列(一)- 代理模式 AOP(Aspect Oriented Programming)并没有创造或使用新的技术,其底层就是基于代理模式实现.因此我们先来学习一下代理模式. 基本概 ...