问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
你好,欢迎来到懂视!登录注册
当前位置: 首页 - 正文

怎么看spring-bootspring-data-redis

发布网友 发布时间:2022-04-09 20:27

我来回答

2个回答

懂视网 时间:2022-04-10 00:48

 

上代码:

 

路由,即实现多数据库的切换源

/*
* 重写的函数决定了最后选择的DataSource
* 因为AbstractRoutingDataSource中获取连接方法为:
@Override
 public Connection getConnection(String username, String password) throws SQLException {
 return determineTargetDataSource().getConnection(username, password);
 }
*/

public class MultiRouteDataSource extends AbstractRoutingDataSource {

 @Override
 protected Object determineCurrentLookupKey() {
 return DataSourceContextHolder.getDataSource();
 }

}

注解,即用以标识选择主还是从数据库

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
 String value();
}

常规配置项,具体主从继承并通过

@ConfigurationProperties(prefix = "master.datasource") 进行配置读取

public class BaseDataSourceConfig {

 private String url;
 private String username;
 private String password;
 private String driverClassName;
 // 添加上getter、setter方法
}

多数据源设置

@Configuration
public class DataSourceComponent {

 @Resource
 MasterDataSourceConfig masterDataSourceConfig;

 @Resource
 FirstDataSourceConfig firstDataSourceConfig;

 @Resource
 SecondDataSourceConfig secondDataSourceConfig;

 /*
 * 一开始以为springboot的自动配置还是会生效,直接加了@Resource DataSource dataSource;
 * 显示是不work的,会报create bean 错误
 */
 public DataSource masterDataSource() {
 DataSource dataSource = new DataSource();
 dataSource.setUrl(masterDataSourceConfig.getUrl());
 dataSource.setUsername(masterDataSourceConfig.getUsername());
 dataSource.setPassword(masterDataSourceConfig.getPassword());
 dataSource.setDriverClassName(masterDataSourceConfig.getDriverClassName());
 return dataSource;
 }

 /*
 * 一开始在这里加了@Bean的注解,当然secondDataSource()也加了
 * 会导致springboot识别的时候,发现有多个
 * 所以,其实都不要加@Bean,最终有效的的DataSource就只需要一个multiDataSource即可
 */
 public DataSource firstDataSource() {
 DataSource dataSource = new DataSource();
 dataSource.setUrl(firstDataSourceConfig.getUrl());
 dataSource.setUsername(firstDataSourceConfig.getUsername());
 dataSource.setPassword(firstDataSourceConfig.getPassword());
 dataSource.setDriverClassName(firstDataSourceConfig.getDriverClassName());
 return dataSource;
 }

 public DataSource secondDataSource() {
 DataSource dataSource = new DataSource();
 dataSource.setUrl(secondDataSourceConfig.getUrl());
 dataSource.setUsername(secondDataSourceConfig.getUsername());
 dataSource.setPassword(secondDataSourceConfig.getPassword());
 dataSource.setDriverClassName(secondDataSourceConfig.getDriverClassName());
 return dataSource;
 }

 @Bean(name = "multiDataSource")
 public MultiRouteDataSource exampleRouteDataSource() {
 MultiRouteDataSource multiDataSource = new MultiRouteDataSource();
 Map<Object, Object> targetDataSources = new HashMap<>();
 targetDataSources.put("master", masterDataSource());
 targetDataSources.put("first", firstDataSource());
 targetDataSources.put("second", secondDataSource());
 multiDataSource.setTargetDataSources(targetDataSources);
 multiDataSource.setDefaultTargetDataSource(masterDataSource());
 return multiDataSource;
 }

 @Bean(name = "transactionManager")
 public DataSourceTransactionManager dataSourceTransactionManager() {
 DataSourceTransactionManager manager = new DataSourceTransactionManager();
 manager.setDataSource(exampleRouteDataSource());
 return manager;
 }

 @Bean(name = "sqlSessionFactory")
 public SqlSessionFactoryBean sqlSessionFactory() {
 SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
 sessionFactoryBean.setDataSource(exampleRouteDataSource());
 return sessionFactoryBean;
 }
}

当然少不了DataSourceContextHolder,用以保持当前线程的数据源选择。

public class DataSourceContextHolder {

 private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

 public static void setDataSource(String value) {
 contextHolder.set(value);
 }

 public static String getDataSource() {
 return contextHolder.get();
 }

 public static void clearDataSource() {
 contextHolder.remove();
 }
}

最后,自然就是AOP+注解实现数据源切换啦

@Aspect
@Component
public class DynamicDataSourceAspect {

 @Around("execution(public * com.wdm.example.service..*.*(..))")
 public Object around(ProceedingJoinPoint pjp) throws Throwable {
 MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
 Method targetMethod = methodSignature.getMethod();
 if(targetMethod.isAnnotationPresent(TargetDataSource.class)){
  String targetDataSource = targetMethod.getAnnotation(TargetDataSource.class).value() ;
  DataSourceContextHolder.setDataSource(targetDataSource);
 }
 Object result = pjp.proceed();
 DataSourceContextHolder.clearDataSource();
 return result;
 }
}

那用法就是如下了:

package com.wdm.example.service;

import java.util.Date;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.wdm.example.dao.UserDao;
import com.wdm.example.datasource.TargetDataSource;
import com.wdm.example.model.User;
import com.wdm.example.service.UserService;

/*
 * @author wdmyong
 * 20170416
 */
@Service
public class UserService {

 @Resource
 UserDao userDao;

 public User getById(Integer id) {
 return userDao.getById(id);
 }

 @TargetDataSource("master")
 public User getById0(Integer id) {
 return userDao.getById(id);
 }

 @TargetDataSource("first")
 public User getById1(Integer id) {
 return userDao.getById(id);
 }

 @TargetDataSource("second")
 public User getById2(Integer id) {
 return userDao.getById(id);
 }

 public void insert(User user) {
 Date now = new Date();
 user.setCreateTime(now);
 user.setModifyTime(now);
 userDao.insert(user);
 }

 public void update(User user) {
 user.setModifyTime(new Date());
 userDao.update(user);
 }

}

自己在网上找的时候不是全的,包括上文注释中提到的出现的问题,也是根据错误提示多个DataSource目标,以及没设置就是没有DataSource了。

 

PS:其实之前一直以为DataSource听起来挺悬乎,没去细想,当然主要由于自己是半路出家的Java、web开发,本身也没那么熟悉,所以没理解哈,

现在想想DataSource其实就是保存了些配置,说白了是url和账号密码,就是连接数据库的,相当于你用命令行连接了数据库进行了操作一样,各种

数据库DataSource的实现高功能多半应该是做了些连接池的管理,以及连接的打开关闭之类,其实实质上我觉得应该就是说最后用的就是那个url加

上账号密码就能连接并操作了。这样的话,多数据源的切换就好理解了,结合 aop 在函数入口之前设置好当前线程数据源,以及根据路由数据库类

AbstractRoutingDataSource将选择数据源留给子类实现的方法

determineCurrentLookupKey,从而在service方法入口设置数据源,在使用时取到数据源。

 

大PS:这应该算是我写的最全的一次Java的博客了!!!

springboot主从数据库

标签:frame   选择   mon   getc   url   获取   子类   methods   key   

热心网友 时间:2022-04-09 21:56

spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化。

redis介绍

Redis是目前业界使用最广泛的内存数据存储。相比memcached,Redis支持更丰富的数据结构,例如hashes, lists,
sets等,同时支持数据持久化。除此之外,Redis还提供一些类数据库的特性,比如事务,HA,主从库。可以说Redis兼具了缓存系统和数据库的一些特性,因此有着丰富的应用场景。本文介绍Redis在Spring
Boot中两个典型的应用场景。

如何使用

1、引入 spring-boot-starter-redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>

2、添加配置文件
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.0.58
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有*)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有*)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

3、添加cache的配置类
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}

@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//设置缓存过期时间
//rcm.setDefaultExpiration(60);//秒
return rcm;
}

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}

}

3、好了,接下来就可以直接使用了
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class TestRedis {

@Autowired
private StringRedisTemplate stringRedisTemplate;

@Autowired
private RedisTemplate redisTemplate;

@Test
public void test() throws Exception {
stringRedisTemplate.opsForValue().set("aaa", "111");
Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
}

@Test
public void testObj() throws Exception {
User user=new User("aa@126.com", "aa", "aa123456", "aa","123");
ValueOperations<String, User> operations=redisTemplate.opsForValue();
operations.set("com.neox", user);
operations.set("com.neo.f", user,1,TimeUnit.SECONDS);
Thread.sleep(1000);
//redisTemplate.delete("com.neo.f");
boolean exists=redisTemplate.hasKey("com.neo.f");
if(exists){
System.out.println("exists is true");
}else{
System.out.println("exists is false");
}
// Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
}
}

以上都是手动使用的方式,如何在查找数据库的时候自动使用缓存呢,看下面;

4、自动根据方法生成缓存
@RequestMapping("/getUser")
@Cacheable(value="user-key")
public User getUser() {
User user=userRepository.findByUserName("aa");
System.out.println("若下面没出现“无缓存的时候调用”字样且能打印出数据表示测试成功");
return user;
}

其中value的值就是缓存到redis中的key
声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。
E-MAIL:11247931@qq.com
连别人的wifi会不会看到我浏览了哪些网站? 电视连接wifi后怎么看网络电视 电脑win7调低亮度win7怎么调整屏幕亮度 电脑屏幕太亮了怎么调暗一点win7windows7怎么调亮度 台式电脑win7 怎么调节屏幕亮度显示器太亮了! win7电脑屏幕一直亮着怎么让电脑屏幕一直亮着 从零开始学作曲(小白入门)【22.11.17更新】 45岁的袁立再次宣布结婚,她这已经是第几次结婚了? dnf怎么洗红字 dnf红字装备怎么改属性 如何去掉word批注如何去掉word批注 梦见把腿上长花了拉出来是虫子就清理了 梦见自己腿上爬了好多虫子是怎么回事 梦见腿上有虫子,去掉后又有个虫子 手机刷机了不用验证码怎么才能登录tiktok,因为以前的手机号不用已经注销了,现在是空号 梦见腿上长虫子!!! 电视机u盘播放格式海信电视支持啥格式 电视机的“u盘”播放是什么格式? 山水音响沈阳维修点在哪? 我买的山水迷你音响MC-3210D6里附带的山水中国区域服务管理中心电话和网址都不存在,是怎么回事? 山水音响山水音响售后服务一流的差劲,使用不到一年,结果维修需一年 天津哪里有山水mc-1301u6音响官方维修站? 哪里可以下载免费而且好听的铃声 如何用springboot连接数据库 我的山水音响坏了,想维修 请问哪里可以修啊? 施工升降机哪个品牌比较靠谱? 山水音响售后服务一流的差劲..10个月后取回音响.. 请问哪里有维修山水音响的 武汉山水电脑音响售后服务电话 珠海有山水音响维修点吗? 电视上用U盘看电影是什么格式的 早上做梦梦见以前住过的房子门前有土堆杂草丛生在整理屋子? 梦见家里特别多的熟鱼堆成山好不好熟? 梦见家里特别多的熟鱼堆成山好不好? 把土变成二可以用一个什么成语表示 男租客退房后屋里垃圾成山,该如何避免这种行为再出现呢? 华为b311-AB33怎么使用 ssh连接linux后怎么编辑.log文件 按揭办不下来买房的首付能退吗 华为B311/B310移动电信联通4G无线路由器三网如何调模式? 房贷下不来,可以要求退首付吗 驾驶机动车在高速公路上不小心错过了出口以下做法错误的是什么? 我想将三个视频同时放在一个屏幕上播放,请问有什么手机软件可以办到 &#xFFFC;在高速公路上驾驶机动车,车辆发生故障后的处置方法,以下说法错误... 雪天在高速公路上行驶时,关于安全车距错误的说法是什么? 华HUAwEi-B311-2C1O忘记密码怎样解锁忘记密码了怎样解锁 题:机动车上高速公路,以下哪种说法是错误的? 雪天在高速公路行驶时说法错误的是 五千驾驶机动车在高速公路遇事故不能继续行驶时以下做法错误的是什么 QQ PC登录怎么登录? 在高速公路上开车,有哪些让人憎恶的不文明、不安全的驾驶行为?
  • 焦点

最新推荐

猜你喜欢

热门推荐