欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Spring?Boot?訪問(wèn)Redis的三種方式

 更新時(shí)間:2022年12月13日 09:12:38   作者:dk168  
這篇文章主要介紹了Spring?Boot?訪問(wèn)Redis的三種方式,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

最近在極客時(shí)間上面學(xué)習(xí)丁雪豐老師的《玩轉(zhuǎn) Spring 全家桶》,其中講到訪問(wèn)Redis的方式,我專門把他們抽出來(lái),在一起對(duì)比下,體驗(yàn)一下三種方式開發(fā)上面的不同, 分別是這三種方式

  • RedisTemplate
  • JPA Repository
  • Cache

開始準(zhǔn)備

開始之前我們需要有Redis安裝,我們采用本機(jī)Docker運(yùn)行Redis, 主要命令如下

docker pull redis
docker run --name my_redis -d -p 6379:6379 redis
docker exec -it my_redis bash
redis-cli

前面兩個(gè)命令是啟動(dòng)redis docker, 后兩個(gè)是連接到docker, 在使用redis-cli 去查看redis里面的內(nèi)容,主要查看我們存在redis里面的數(shù)據(jù)。

RedisTemplate

我們先從RedisTemplate開始,這個(gè)是最好理解的一種方式,我之前在工作中也使用過(guò)這種方式,先看代碼示例
我們先定義一個(gè)POJO類

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Book implements Serializable {
    private Long id;
    private String name;

    private String author;
}

一個(gè)很簡(jiǎn)單的BOOK類,三個(gè)字段: id,name和author.
再來(lái)一個(gè)RedisTemplate的Bean

    @Bean
    public RedisTemplate<String, Book> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Book> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

再定義一個(gè)使用這個(gè)RedisTemplate的Service類

    public Optional<Book> findOneBook(String name) {
        HashOperations<String, String, Book> hashOperations = redisTemplate.opsForHash();
        if (redisTemplate.hasKey(CACHE) && hashOperations.hasKey(CACHE, name)) {
            log.info("Get book {} from Redis.", name);
            return Optional.of(hashOperations.get(CACHE, name));
        }

        Optional<Book> book = bookRepository.getBook(name);
        log.info("Book Found: {}", book);
        if (book.isPresent()) {
            log.info("Put book {} to Redis.", name);
            hashOperations.put(CACHE, name, book.get());
            redisTemplate.expire(CACHE, 10, TimeUnit.MINUTES);
        }
        return book;
    }

我們使用Hash來(lái)存儲(chǔ)這個(gè)Book信息,在上面的方法中查找書名存不存在Redis中,如果存在就直接返回,如果不存在就去持久化存儲(chǔ)中找,找到就再通過(guò)Template寫入到Redis中, 這是緩存的通用做法。 使用起來(lái)感覺(jué)很方便。
我們這里為了簡(jiǎn)單沒(méi)有使用持久化存儲(chǔ),就硬編碼了幾條數(shù)據(jù), 代碼如下

@Repository
public class BookRepository {
    Map<String, Book> bookMap = new HashMap<>();
    public BookRepository(){
        bookMap.put("apache kafka", Book.builder()
                .name("apache kafka").id(1L).author("zhangsan")
                .build());
        bookMap.put("python", Book.builder()
                .name("python").id(2L).author("lisi")
                .build());
    }

    public Optional<Book> getBook(String name){
        if(bookMap.containsKey(name)){
            return Optional.of(bookMap.get(name));
        }
        else{
            return Optional.empty();
        }
    }
}

我們調(diào)用 bookService.findOneBook("python")和bookService.findOneBook("apache kafka"); 來(lái)把數(shù)據(jù)寫入到換存中

我們來(lái)看下存儲(chǔ)在Redis的數(shù)據(jù)長(zhǎng)什么樣子。

127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04book"
127.0.0.1:6379> type "\xac\xed\x00\x05t\x00\x04book"
hash
127.0.0.1:6379> hgetall "\xac\xed\x00\x05t\x00\x04book"
1) "\xac\xed\x00\x05t\x00\x06python"
2) "\xac\xed\x00\x05sr\x00&com.ken.redistemplatesample.model.Book=\x19\x96\xfb\x7f\x7f\xda\xbe\x02\x00\x03L\x00\x06authort\x00\x12Ljava/lang/String;L\x00\x02idt\x00\x10Ljava/lang/Long;L\x00\x04nameq\x00~\x00\x01xpt\x00\x04lisisr\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\x00\x00\x00\x00\x00\x02t\x00\x06python"
3) "\xac\xed\x00\x05t\x00\x0capache kafka"
4) "\xac\xed\x00\x05sr\x00&com.ken.redistemplatesample.model.Book=\x19\x96\xfb\x7f\x7f\xda\xbe\x02\x00\x03L\x00\x06authort\x00\x12Ljava/lang/String;L\x00\x02idt\x00\x10Ljava/lang/Long;L\x00\x04nameq\x00~\x00\x01xpt\x00\bzhangsansr\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\x00\x00\x00\x00\x00\x01t\x00\x0capache kafka"

我們可以看到數(shù)據(jù)被存在了key是“\xac\xed\x00\x05t\x00\x04book”的一個(gè)Hash表中, Hash里面有兩條記錄。 大家發(fā)現(xiàn)一個(gè)問(wèn)題沒(méi)有? 就是這個(gè)key不是我們想象的用“book”做key,而是多了一串16進(jìn)制的碼, 這是因?yàn)镽edisTemplate使用了默認(rèn)的JdkSerializationRedisSerializer 去序列化我們的key和value, 如果大家都用Java語(yǔ)言那沒(méi)有問(wèn)題, 如果有人用Java語(yǔ)言寫,有人用別的語(yǔ)言讀,那就有問(wèn)題,就像我開始的時(shí)候用hgetall "book"始終拿不到數(shù)據(jù)那樣。
RedisTemplate也提供了StringRedisTemplate來(lái)方便大家需要使用String來(lái)序列化redis里面的數(shù)據(jù)。簡(jiǎn)單看下代碼

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
    {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
	
    public Optional<String> getBookString(String name){
        HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
        if (stringRedisTemplate.hasKey(STRINGCACHE) && hashOperations.hasKey(STRINGCACHE, name)) {
            log.info("Get book {} from Redis.", name);
            return Optional.of(hashOperations.get(STRINGCACHE, name));
        }

        Optional<Book> book = bookRepository.getBook(name);
        log.info("Book Found: {}", book);
        if (book.isPresent()) {
            log.info("Put book {} to Redis.", name);
            hashOperations.put(STRINGCACHE, name, book.get().getAuthor());
            stringRedisTemplate.expire(STRINGCACHE, 10, TimeUnit.MINUTES);
            return Optional.of(book.get().getAuthor());
        }
        return Optional.empty();
    }

使用上就沒(méi)有那么方便,你就得自己寫需要存的是哪個(gè)字段,讀出來(lái)是哪個(gè)字段。

127.0.0.1:6379> keys *
1) "string_book"
127.0.0.1:6379> hgetall string_book
1) "python"
2) "lisi"
3) "apache kafka"
4) "zhangsan"

如上圖所示,使用客戶端讀出來(lái)看起來(lái)就比較清爽一些。也可以看到占用的Size會(huì)小很多,我們這個(gè)例子相差7倍,如果是數(shù)據(jù)量大,這個(gè)還是比較大的浪費(fèi)。

127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04book"
2) "string_book"
127.0.0.1:6379> memory usage "string_book"
(integer) 104
127.0.0.1:6379> memory usage "\xac\xed\x00\x05t\x00\x04book"
(integer) 712

JPA Repository

我們知道使用JPA Repository來(lái)訪問(wèn)DataBase的時(shí)候,增刪改查那樣的操作能夠很方便的實(shí)現(xiàn),基本就是定義個(gè)接口,代碼都不用寫,Spring就幫我們完成了大部分的工作,那么訪問(wèn)Redis是不是也可以這樣呢? 答案是肯定的,我們來(lái)看代碼
首先我們還是定義一個(gè)POJO

@RedisHash(value = "cache-book", timeToLive = 600)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CacheBook implements Serializable {

    @Id
    private Long userId;

    @Indexed
    private String name;

    private String author;
}

這個(gè)類與我們上面template上面的類的區(qū)別就是我們加了兩個(gè)注解, 在類開頭加了
@RedisHash(value = "cache-book", timeToLive = 600)
在字段上面加了@Id和@Indexed
定義一個(gè)Repository的接口

public interface CacheBookRepository extends CrudRepository<CacheBook, Long> {
    Optional<CacheBook> findOneByName(String name);
}

再定義一個(gè)service和上面那個(gè)例子template一樣,緩存中有就到緩存中拿,沒(méi)有就到持久化存儲(chǔ)中找,并寫入緩存

@Slf4j
@Service
public class BookService {
    private static final String CACHE = "repository-book";
    @Autowired
    private CacheBookRepository cacheRepository;

    @Autowired
    private BookRepository bookRepository;

    public Optional<CacheBook> findOneBook(String name) {
        Optional<CacheBook> optionalCacheBook = cacheRepository.findOneByName(name);
        if(!optionalCacheBook.isPresent())
        {
            Optional<CacheBook> book = bookRepository.getBook(name);
            log.info("Book Found: {}", book);
            if (book.isPresent()) {
                log.info("Put book {} to Redis.", name);
                cacheRepository.save(book.get());
            }
            return book;
        }
        return optionalCacheBook;
    }
}

代碼很簡(jiǎn)單,簡(jiǎn)單到不敢相信是真的。
還是一樣,調(diào)用這個(gè)方法,我們來(lái)看存在Redis里面的數(shù)據(jù)

127.0.0.1:6379> keys *
1) "repository-book:2"
2) "repository-book:2:idx"
3) "repository-book"
4) "repository-book:name:apache kafka"
5) "repository-book:name:python"
6) "repository-book:1:idx"
7) "repository-book:1"

哇,感覺(jué)存的內(nèi)容有些多, 不用怕我們來(lái)看下各自存什么數(shù)據(jù)
首先看最短的一個(gè)

127.0.0.1:6379> smembers repository-book
1) "1"
2) "2"

它里面存的是我們的id所有的value, 可以用來(lái)判斷id是否存在
再來(lái)看

127.0.0.1:6379> hgetall repository-book:2
1) "_class"
2) "com.ken.redisrepositorysample.model.CacheBook"
3) "author"
4) "lisi"
5) "name"
6) "python"
7) "userId"
8) "2"

這個(gè)是我們數(shù)據(jù)存放的地方

127.0.0.1:6379> smembers repository-book:1:idx
1) "repository-book:name:apache kafka"
127.0.0.1:6379> smembers "repository-book:name:apache kafka"
1) "1"

另外兩個(gè)都是set, 存在在它們里面的數(shù)據(jù)是索引信息。
由此可以看出通過(guò)JPA Repository 的方式,代碼很少,而且存儲(chǔ)的數(shù)據(jù)也很通用,個(gè)人覺(jué)得是比較理想的訪問(wèn)方法。

Cache

我們已經(jīng)看了兩種方式,在訪問(wèn)的時(shí)候遵循這樣的模式:緩存中有就從緩存中返回,沒(méi)有就從持久化存儲(chǔ)中找,然后寫入緩存,這部分代碼我也不想自己寫,那么Cache就是你的救星。
我們先看代碼
我們這次使用內(nèi)存數(shù)據(jù)庫(kù)H2作為持久化存儲(chǔ), 放一個(gè)schema.sql在resouces下面

drop table t_book if exists;
create table t_book (
    id bigint auto_increment,
    create_time timestamp,
    update_time timestamp,
    name varchar(255),
    author varchar(200),
    primary key (id)
);
insert into t_book (name, author, create_time, update_time) values ('python', 'zhangsan', now(), now());
insert into t_book (name, author, create_time, update_time) values ('hadoop', 'lisi', now(), now());
insert into t_book (name, author, create_time, update_time) values ('java', 'wangwu', now(), now());

然后定義POJO

@Entity
@Table(name = "T_BOOK")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CacheBook implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String author;

    @Column(updatable = false)
    @CreationTimestamp
    private Date createTime;
    @UpdateTimestamp
    private Date updateTime;
}

完全是和數(shù)據(jù)庫(kù)綁定的代碼,和緩存沒(méi)有任何關(guān)系
一個(gè)Repository來(lái)訪問(wèn)數(shù)據(jù)庫(kù)

public interface BookRepository extends JpaRepository<CacheBook, Long> {
}

定義一個(gè)service來(lái)調(diào)用它

@Slf4j
@Service
@CacheConfig(cacheNames = "cache-book")
public class BookService {

    @Autowired
    private BookRepository bookRepository;

    @Cacheable
    public List<CacheBook> findAllCoffee() {
        return bookRepository.findAll();
    }

    @CacheEvict
    public void reloadCoffee() {
    }
}

這里就比較關(guān)鍵了,在類上加上了注解
@CacheConfig(cacheNames = "cache-book")
在方法上面加上了Cacheable和CacheEvict, Cacheable這個(gè)方法就是用來(lái)實(shí)現(xiàn)邏輯,有就從緩存中拿,沒(méi)有就從數(shù)據(jù)庫(kù)拿的,CacheEvict是調(diào)用這個(gè)方法的時(shí)候清除緩存。
然后再啟動(dòng)入口程序的地方加上注解
@EnableJpaRepositories
@EnableCaching(proxyTargetClass = true)
在配置文件application.properties中加上

spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

management.endpoints.web.exposure.include=*

spring.cache.type=redis
spring.cache.cache-names=cache-book
spring.cache.redis.time-to-live=600000
spring.cache.redis.cache-null-values=false

spring.redis.host=localhost

這樣就可以了, 感覺(jué)就是通過(guò)配置下就把緩存給完成了,非常的簡(jiǎn)單
我們來(lái)看Redis中是怎么存的

127.0.0.1:6379> keys *
1) "cache-book::SimpleKey []"
127.0.0.1:6379> get "cache-book::SimpleKey []"
"\xac\xed\x00\x05sr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x03w\x04\x00\x00\x00\x03sr\x00(com.ken.rediscachesample.model.CacheBook\xec\xcbR=\xe1U\x9b\xf7\x02\x00\x05L\x00\x06authort\x00\x12Ljava/lang/String;L\x00\ncreateTimet\x00\x10Ljava/util/Date;L\x00\x02idt\x00\x10Ljava/lang/Long;L\x00\x04nameq\x00~\x00\x03L\x00\nupdateTimeq\x00~\x00\x04xpt\x00\bzhangsansr\x00\x12java.sql.Timestamp&\x18\xd5\xc8\x01S\xbfe\x02\x00\x01I\x00\x05nanosxr\x00\x0ejava.util.Datehj\x81\x01KYt\x19\x03\x00\x00xpw\b\x00\x00\x01\x84\xff]\x85\xb0x\b-\x81\x80sr\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\x00\x00\x00\x00\x00\x01t\x00\x06pythonsq\x00~\x00\bw\b\x00\x00\x01\x84\xff]\x85\xb0x\b-\x81\x80sq\x00~\x00\x02t\x00\x04lisisq\x00~\x00\bw\b\x00\x00\x01\x84\xff]\x85\xb0x\b<\xbf\xd8sq\x00~\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x02t\x00\x06hadoopsq\x00~\x00\bw\b\x00\x00\x01\x84\xff]\x85\xb0x\b<\xbf\xd8sq\x00~\x00\x02t\x00\x06wangwusq\x00~\x00\bw\b\x00\x00\x01\x84\xff]\x85\xb0x\b<\xbf\xd8sq\x00~\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x03t\x00\x04javasq\x00~\x00\bw\b\x00\x00\x01\x84\xff]\x85\xb0x\b<\xbf\xd8x"

看到?jīng)]有,就是當(dāng)成Redis里面的String來(lái)存的, 如果數(shù)據(jù)量比較小,那是非常的方便,如果數(shù)據(jù)量大,這種方式就有些問(wèn)題了。

總結(jié)

我們看了這三種方式,這里僅僅是做了個(gè)入門,每個(gè)里面都有很多細(xì)節(jié)的地方需要去研究和使用,整體的感覺(jué)是要想使用的簡(jiǎn)單,那么存儲(chǔ)在Redis中的數(shù)據(jù)就要量少,量大后,就需要自己來(lái)定制了,那基本上要用RedisTemplate來(lái)做一些工作。 這三個(gè)程序比較簡(jiǎn)單,我也把它放在github上面了, https://github.com/dengkun39/redisdemo.git

到此這篇關(guān)于詳解Spring Boot 訪問(wèn)Redis的三種方式的文章就介紹到這了,更多相關(guān)Spring Boot 訪問(wèn)Redis內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解析Redis 數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單動(dòng)態(tài)字符串sds

    解析Redis 數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單動(dòng)態(tài)字符串sds

    Redis 的 string 類型為何使用sds而不是 C 字符串,本文主要介紹 string 的數(shù)據(jù)結(jié)構(gòu)—— 簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String) 簡(jiǎn)稱sds的相關(guān)知識(shí),需要的朋友可以參考下
    2021-11-11
  • Redis教程(九):主從復(fù)制配置實(shí)例

    Redis教程(九):主從復(fù)制配置實(shí)例

    這篇文章主要介紹了Redis教程(九):主從復(fù)制配置實(shí)例,本文講解了Redis的Replication、Replication的工作原理、如何配置Replication、應(yīng)用示例等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • 使用lua+redis解決發(fā)多張券的并發(fā)問(wèn)題

    使用lua+redis解決發(fā)多張券的并發(fā)問(wèn)題

    這篇文章主要介紹了使用lua+redis解決發(fā)多張券的并發(fā)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Redis序列化存儲(chǔ)及日期格式的問(wèn)題處理

    Redis序列化存儲(chǔ)及日期格式的問(wèn)題處理

    這篇文章主要介紹了Redis序列化存儲(chǔ)及其日期格式的問(wèn)題處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Redis實(shí)現(xiàn)延遲任務(wù)的常見(jiàn)方案詳解

    Redis實(shí)現(xiàn)延遲任務(wù)的常見(jiàn)方案詳解

    延遲任務(wù)(Delayed?Task)是指在未來(lái)的某個(gè)時(shí)間點(diǎn),執(zhí)行相應(yīng)的任務(wù),本文為大家整理了Redis實(shí)現(xiàn)延遲任務(wù)的幾個(gè)常見(jiàn)方案,希望對(duì)大家有所幫助
    2024-04-04
  • Redis分析慢查詢操作的實(shí)例教程

    Redis分析慢查詢操作的實(shí)例教程

    這篇文章主要給大家介紹了關(guān)于Redis如何分析慢查詢操作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Redis 出現(xiàn)錯(cuò)誤1067的解決辦法

    Redis 出現(xiàn)錯(cuò)誤1067的解決辦法

    這篇文章主要介紹了Redis 出現(xiàn)錯(cuò)誤1067的解決辦法的相關(guān)資料,Redis 錯(cuò)誤1067:進(jìn)程意外終止,Redis不能啟動(dòng),Redis啟動(dòng)不了,需要的朋友可以參考下
    2017-07-07
  • Redis中的bitmap詳解

    Redis中的bitmap詳解

    BitMap是通過(guò)一個(gè)bit位來(lái)表示某個(gè)元素對(duì)應(yīng)的值或者狀態(tài),其中的key就是對(duì)應(yīng)元素本身。我們知道8個(gè)bit可以組成一個(gè)Byte,所以bitmap本身會(huì)極大的節(jié)省儲(chǔ)存空間,下面通過(guò)本文給大家介紹Redis中的bitmap知識(shí),感興趣的朋友一起看看吧
    2021-10-10
  • Redis中的BigKey問(wèn)題排查與解決思路詳解

    Redis中的BigKey問(wèn)題排查與解決思路詳解

    Redis是一款性能強(qiáng)勁的內(nèi)存數(shù)據(jù)庫(kù),但是在使用過(guò)程中,我們可能會(huì)遇到Big Key問(wèn)題,這個(gè)問(wèn)題就是Redis中某個(gè)key的value過(guò)大,所以Big Key問(wèn)題本質(zhì)是Big Value問(wèn)題,這篇文章主要介紹了Redis中的BigKey問(wèn)題:排查與解決思路,需要的朋友可以參考下
    2023-03-03
  • mac下redis安裝、設(shè)置、啟動(dòng)停止方法詳解

    mac下redis安裝、設(shè)置、啟動(dòng)停止方法詳解

    這篇文章主要介紹了mac下redis安裝、設(shè)置、啟動(dòng)停止方法詳解,需要的朋友可以參考下
    2020-02-02

最新評(píng)論