SpringBoot Redis緩存

關(guān)于redis的安裝、配置及啟動,參考Redis簡單配置使用

1.添加依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2.添加配置文件

#Redis數(shù)據(jù)庫索引(默認(rèn)為0)
spring.redis.database=0
#Redis服務(wù)器地址
spring.redis.host=localhost
#Redis服務(wù)器連接端口
spring.redis.port=6379
#Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=123456
#連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
spring.redis.pool.max-active=8
#連接池最大阻塞等待時間(使用負(fù)值表示沒有限制)
spring.redis.pool.max-wait=-1
#連接池中的最大空閑連接
spring.redis.pool.max-idle=8
#連接池中的最小空閑連接
spring.redis.pool.min-idle=0
#連接超時時間(毫秒)
spring.redis.timeout=1000

3.添加配置類

Redis 不是應(yīng)用的共享內(nèi)存钢属,它只是一個內(nèi)存服務(wù)器,就像 MySql 门躯,我們需要將應(yīng)用連接到它并使用某種“語言”進行交互淆党,因此我們還需要一個連接工廠以及一個 Spring 和 Redis 對話要用的 RedisTemplate,這些都是 Redis 緩存所必需的配置.

Redis 可以存儲鍵與5種不同數(shù)據(jù)結(jié)構(gòu)類型之間的映射讶凉,這5種數(shù)據(jù)結(jié)構(gòu)類型分別為String(字符串)染乌、List(列表)、Set(集合)懂讯、Hash(散列)和 Zset(有序集合)慕匠。

代碼:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

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

// 要啟用緩存支持,我們需要創(chuàng)建一個新的 CacheManager bean
    @SuppressWarnings("rawtypes")
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager manager = new RedisCacheManager(redisTemplate);
        return manager;
    }


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

以下內(nèi)容是針對上面配置的一些解釋說明:

1.關(guān)于public KeyGenerator keyGenerator():
對于使用 @Cacheable 注解的方法域醇,每個緩存的 key 生成策略默認(rèn)使用的是參數(shù)名+參數(shù)值台谊,比如以下方法:

@Cacheable("users")
public User findByUsername(String username)

這個方法的緩存將保存于 key 為 users~keys 的緩存下蓉媳,對于 username 取值為 "趙德芳" 的緩存,key 為 "username-趙德芳"锅铅。一般情況下沒啥問題酪呻,但是如果方法 key 取值相等然后參數(shù)名也一樣的時候就出問題了,如:

@Cacheable("users")
public Integer getLoginCountByUsername(String username)

這個方法的緩存也將保存于 key 為 users~keys 的緩存下盐须。對于 username 取值為 "趙德芳" 的緩存玩荠,key 也為 "username-趙德芳",將另外一個方法的緩存覆蓋掉贼邓。

解決辦法是使用自定義緩存策略阶冈,對于同一業(yè)務(wù)(同一業(yè)務(wù)邏輯處理的方法,哪怕是集群/分布式系統(tǒng))塑径,生成的 key 始終一致女坑,對于不同業(yè)務(wù)則不一致:

于是上述兩個方法,對于 username 取值為 "趙德芳" 的緩存统舀,雖然都還是存放在 key 為 users~keys 的緩存下匆骗,但由于 key 分別為 "類名-findByUsername-username-趙德芳" 和 "類名-getLoginCountByUsername-username-趙德芳",所以也不會有問題誉简。

這對于集群系統(tǒng)碉就、分布式系統(tǒng)之間共享緩存很重要,真正實現(xiàn)了分布式緩存闷串。

2.RedisTemplate:
spring 封裝了 RedisTemplate 對象來進行對redis的各種操作瓮钥,它支持所有的 redis 原生的 api。
RedisTemplate默認(rèn)采用的是JDK的序列化策略烹吵,保存的key和value都是采用此策略序列化保存的碉熄。因此被緩存對象需要實現(xiàn)java.io.Serializable接口,否則緩存出錯年叮。(比如后面要用到的User)。

RedisTemplate中定義了對5種數(shù)據(jù)結(jié)構(gòu)操作

     redisTemplate.opsForValue();//操作字符串
     redisTemplate.opsForHash();//操作hash
     redisTemplate.opsForList();//操作list
     redisTemplate.opsForSet();//操作set
     redisTemplate.opsForZSet();//操作有序set

模板中的Redis key的類型(通常為String)如:RedisTemplate<String, Object>
注意:如果沒特殊情況玻募,切勿定義成RedisTemplate<Object, Object>只损,否則根據(jù)里氏替換原則,使用的時候會造成類型錯誤 七咧。

3.StringRedisTemplate與RedisTemplate

兩者的關(guān)系是StringRedisTemplate繼承RedisTemplate跃惫。

兩者的數(shù)據(jù)是不共通的;也就是說StringRedisTemplate只能管理StringRedisTemplate里面的數(shù)據(jù)艾栋,RedisTemplate只能管理RedisTemplate中的數(shù)據(jù)爆存。

SDR默認(rèn)采用的序列化策略有兩種,一種是String的序列化策略蝗砾,一種是JDK的序列化策略先较。

StringRedisTemplate默認(rèn)采用的是String的序列化策略携冤,保存的key和value都是采用此策略序列化保存的。

4.定一個User類

//RedisTemplate下被緩存的對象一定要實現(xiàn)Serializable接口
public class User implements Serializable {

    private String name;
    private int age;
    private String email;

    public User() {
        super();
    }


    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

5.測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    public void contextLoads() {

        stringRedisTemplate.opsForValue().set("myKey", "123456");
        System.out.println(stringRedisTemplate.opsForValue().get("myKey"));
    }

    @Test
    public void testObj() throws Exception {

        User user = new User("archerLj", 27, "lj0011977@163.com");
        ValueOperations<String, User> operations = redisTemplate.opsForValue();
        operations.set("myUser", user);
        operations.set("myUser2", user,1, TimeUnit.MINUTES); //設(shè)置緩存過期時間為1分鐘闲勺。
        Thread.sleep(60000);

        boolean exists = redisTemplate.hasKey("myUser");
        if (exists) {
            System.out.println("key myUser exists");
        } else {
            System.out.println("key myUser not exists");
        }

        boolean exists2 = redisTemplate.hasKey("myUser2");
        if (exists2) {
            System.out.println("key myUser2 exists");
        } else {
            System.out.println("key myUser2 not exists");
        }
    }
}

----------------------下面是注解方式的使用-----------

1.添加以下依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

使用mysql數(shù)據(jù)庫曾棕,JPA來做數(shù)據(jù)操作。

2.定義實體類User

package com.example.demo.domain;
@Entity
public class User implements Serializable {

    @Id
    private int id;
    private String name;
    private int age;
    private String email;

    public User() {
        super();
    }


    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

3. 在啟動類添加實體類掃描目錄并開啟緩存菜循。

@EnableCaching
@ComponentScan("com.example.demo.domain")
public class DemoApplication {}

4.UserRepository接口定義

@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {

    @Cacheable(key = "#p0")
    User findByName(String name);

    @CachePut(key = "#p0.name")
    User save(User user);
}

5.啟動類添加兩個請求:

@RestController
@SpringBootApplication
@EnableCaching
@ComponentScan("com.example.demo.domain")
public class DemoApplication {

    @Autowired
    UserRepository userRepository;

    @RequestMapping("/getUser")
    public User getUser() {
        User user = userRepository.findByName("archerLj");
        return user;
    }

    @RequestMapping("/save")
    public User save() {
        User user = userRepository.findByName("archerLj");
        user.setAge(102);
        return userRepository.save(user);
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

6.修改配置

spring.datasource.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
spring.jpa.properties.hibernate.show_sql=true

數(shù)據(jù)庫:

use test1;
create table User(
id int primary key auto_increment,
name varchar(20),
age int,
email varchar(30)
) default charset=utf8;

insert into test1.User(name, age, email) values("archerLj", 27, "lj0011977@163.com");

7.測試:

訪問http://localhost:8080/getUser翘地,第一次訪問,后臺會打印sql語句癌幕,第二次訪問會直接從緩存中獲取衙耕,不會再打印sql。
訪問http://localhost:8080/save來修改用戶的age屬性勺远,再訪問http://localhost:8080/getUser橙喘,發(fā)現(xiàn)沒有打印sql,但age屬性已經(jīng)隨著修改了谚中。修改的數(shù)據(jù)之所以能同步到緩存中渴杆,是因為@CachePut注解起的作用。

最終demo

參考:
如何使用RedisTemplate訪問Redis數(shù)據(jù)結(jié)構(gòu)
springboot(三):Spring boot中Redis的使用
Spring Boot中的緩存支持(二)使用Redis做集中式緩存

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宪塔,一起剝皮案震驚了整個濱河市磁奖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌某筐,老刑警劉巖比搭,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異南誊,居然都是意外死亡身诺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門抄囚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霉赡,“玉大人,你說我怎么就攤上這事幔托⊙鳎” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵重挑,是天一觀的道長嗓化。 經(jīng)常有香客問我,道長谬哀,這世上最難降的妖魔是什么刺覆? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮史煎,結(jié)果婚禮上谦屑,老公的妹妹穿的比我還像新娘驳糯。我一直安慰自己,他們只是感情好伦仍,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布结窘。 她就那樣靜靜地躺著,像睡著了一般充蓝。 火紅的嫁衣襯著肌膚如雪隧枫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天谓苟,我揣著相機與錄音官脓,去河邊找鬼。 笑死涝焙,一個胖子當(dāng)著我的面吹牛卑笨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仑撞,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赤兴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了隧哮?” 一聲冷哼從身側(cè)響起桶良,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沮翔,沒想到半個月后陨帆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡采蚀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年疲牵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榆鼠。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡纲爸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妆够,到底是詐尸還是另有隱情识啦,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布责静,位于F島的核電站袁滥,受9級特大地震影響盖桥,放射性物質(zhì)發(fā)生泄漏灾螃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一揩徊、第九天 我趴在偏房一處隱蔽的房頂上張望腰鬼。 院中可真熱鬧嵌赠,春花似錦、人聲如沸熄赡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彼硫。三九已至炊豪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拧篮,已是汗流浹背词渤。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留串绩,地道東北人缺虐。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像礁凡,于是被迫代替她去往敵國和親高氮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理顷牌,服務(wù)發(fā)現(xiàn)剪芍,斷路器,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 時間有時會被停格在某個特別的瞬間,比如在燥熱中的高考疗锐,比如在深夜的哭泣坊谁,比如在被愛的溫暖。等等 是啊滑臊,總是被這些那...
    世俗女子閱讀 918評論 19 15
  • 丹心碧血劍口芍,青鋒俠客行。 白馬西風(fēng)嘯雇卷,飛狐雪山情鬓椭。 逐鹿笑問鼎,射雕傲群英关划。 恩仇何須書小染,江湖自留名。
    馬大狀閱讀 204評論 0 1
  • deleted.
    熱心市民X先生閱讀 849評論 0 26
  • 作者| silenceboy My name is Linus Torvalds and I am your go...
    那個小碼哥閱讀 1,878評論 1 3