¿Solo hay RedisTemplate para operar Redis?

¿Sigues usando RedisTemplate solo para acceder a Redis? ¡Aquí hay algunas maneras de organizarlo para usted!

imagen

  • empieza a prepararte
  • Plantilla Redis
  • Repositorio JPA
  • Cache
  • Resumir

empieza a prepararte

Antes de comenzar, necesitamos tener Redis instalado. Usamos el Docker local para ejecutar Redis. Los comandos principales son los siguientes

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

Los dos primeros comandos son para iniciar redis docker, y los dos últimos son para conectarse a docker.Utilice redis-cli para ver el contenido en redis, principalmente para ver los datos que tenemos en redis.

Plantilla Redis

Comencemos con RedisTemplate. Esta es la mejor manera de entender. He usado este método en mi trabajo antes. Veamos primero el ejemplo de código. Definamos una clase POJO

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

Una clase BOOK muy simple, tres campos: id, namey author. otro RedisTemplatefrijol

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

Luego defina una clase de servicio que use este RedisTemplate

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;
}

Usamos Hash para almacenar la información de este Libro. En el método anterior, podemos encontrar si el título del libro existe en Redis. Si existe, lo devolveremos directamente. Si no existe, lo encontraremos en el persistente almacenamiento Si lo encontramos, lo escribiremos en Redis a través de Plantilla, que es una práctica común para el almacenamiento en caché. Se siente muy cómodo de usar.

En aras de la simplicidad, no usamos almacenamiento persistente aquí, por lo que codificamos algunos datos, el código es el siguiente

@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();
        }
    }
}

Llamamos bookService.findOneBook("python")y bookService.findOneBook("apache kafka");escribimos datos al swap

Echemos un vistazo a cómo se ven los datos almacenados en Redis.

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"

Podemos ver que los datos se almacenan \xac\xed\x00\x05t\x00\x04booken una tabla Hash cuya clave es " ", y hay dos registros en el Hash. ¿Encontraste algún problema?

Es decir, la clave no es la clave "libro" que imaginamos, sino una cadena de códigos hexadecimales. Esto se debe a que RedisTemplate usa el valor predeterminado para JdkSerializationRedisSerializerserializar nuestra clave y valor. Si todos usan el lenguaje Java, entonces no hay problema, si alguien escribe en Java y alguien lee en otro idioma, habrá un problema, al igual que cuando usé hgetall "libro" al principio, no pude obtener los datos.

RedisTemplateTambién se proporciona StringRedisTemplatepara facilitar que todos los que necesitan usar String serialicen los datos en redis. Solo mira el código

@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();
}

No es tan conveniente de usar, debe escribir qué campo guardar y qué campo leer.

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"

Como se muestra en la figura anterior, parece más refrescante usar el cliente para leerlo. También se puede ver que el Tamaño ocupado será mucho más pequeño. En nuestro ejemplo, la diferencia es 7 veces. Si la cantidad de datos es grande, esto sigue siendo un desperdicio relativamente grande.

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

Repositorio JPA

Sabemos que al usar JPA Repository para acceder a DataBase, operaciones como agregar, eliminar, modificar y verificar se pueden realizar fácilmente. Básicamente, es definir una interfaz sin escribir código. Spring nos ayudará a completar la mayor parte del trabajo. Luego, acceder ¿Redis?, ¿puede ser así? La respuesta es sí, primero veamos el código, todavía definimos un 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;
}

La diferencia entre esta clase y la clase sobre nuestra plantilla es que agregamos dos anotaciones, agregamos al comienzo de la clase, @RedisHash(value = "cache-book", timeToLive = 600) agregamos @Idy @Indexeddefinimos una Repositoryinterfaz en el campo

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

Luego defina un servicio como la plantilla en el ejemplo anterior. Si hay uno en el caché, obténgalo del caché. Si no, búsquelo en el almacenamiento persistente y escríbalo en el caché.

@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;
    }
}

El código es tan simple, tan simple que no puedo creer que sea verdad. Sigue igual, llame a este método, veamos los datos almacenados en Redis

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"

Wow, siento que hay mucho contenido almacenado, no se asusten, echemos un vistazo a qué datos se almacenan en cada uno, primero miren el más corto.

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

Almacena todos los valores de nuestra identificación, que se pueden usar para determinar si existe la identificación y luego mirarla

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"

Aquí es donde se almacenan nuestros datos.

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"

Los otros dos son conjuntos y los datos almacenados en ellos son información de índice. De esto se puede ver que a través del método JPA Repository, el código es muy pequeño y los datos almacenados también son muy comunes.Personalmente, creo que es un método de acceso ideal.

Cache

Ya hemos visto dos formas y seguimos este patrón al acceder: si hay algo en el caché, devuélvalo del caché, si no, búsquelo en el almacenamiento persistente y luego escríbalo en el caché. salvador.

Veamos primero el código. Esta vez usamos la base de datos de memoria H2 como almacenamiento persistente y colocamos una schema.sqlen recursos

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());

Luego define el 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;
}

Está completamente enlazado con código a la base de datos y no tiene nada que ver con el almacenamiento en caché.

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

Definir un servicio para llamarlo

@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() {
    
    
    }
}

Aquí está el punto clave. Se agregan anotaciones a la clase, y Cacheable y CacheEvict se agregan @CacheConfig(cacheNames = "cache-book") al método. El método Cacheable se usa para implementar la lógica. Si hay uno, se tomará del caché. Si no, se se tomará de la base de datos CacheEvict es llamar a este método para borrar el caché.

Luego agregue un comentario al lugar donde se inicia el programa de entrada Agregar @EnableJpaRepositories @EnableCaching(proxyTargetClass = true) al application.propertiesarchivo de configuración

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

Eso es todo. Parece que el caché se completa a través de la configuración. Es muy simple. Veamos cómo se almacena en 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"

Si no lo ve, se almacena como un String en Redis. Si la cantidad de datos es relativamente pequeña, es muy conveniente. Si la cantidad de datos es grande, este método tiene algunos problemas.

Resumir

Hemos analizado estos tres métodos, y aquí es solo una introducción. Hay muchos detalles en cada uno de los cuales deben estudiarse y usarse. La sensación general es que si desea usarlo fácilmente, entonces los datos almacenados en Redis deben be Si la cantidad es pequeña y la cantidad es grande, debe personalizarlo usted mismo Básicamente, necesita usar RedisTemplate para hacer algo de trabajo.

Supongo que te gusta

Origin blog.csdn.net/aq_money/article/details/130358262
Recomendado
Clasificación