Redis——作為sql數據庫緩存


一、環境springBoot:

  1)導入依賴:

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

  2)配置文件 application.yml

spring:
  redis:
    host: 192.168.2.147
    port: 6379
    password: java1902
    jedis:
      pool:
        max-active: 100
application.yml

二、redis作為數據庫緩存:

  原理:第一次查詢使用sql數據庫,查詢完成后把數據存入redis用於后續查詢,直到sql中的數據變化,清空相應的redis緩存,重新獲取;

  緩存失效:更新數據庫,采用清空redis緩存的方式;

  1)實體類:

public class Product implements Serializable {
    private Integer id;
    private String name;

    public Product() {
    }

    public Product(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
實體類

  2)測試:

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedistestSpringData2ApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void cacheTest() {
        List<Product> products = (List<Product>) redisTemplate.opsForValue().get("product:");
        if (products == null) {
            System.out.println("查詢數據庫......");
            // 模擬從數據庫查詢數據
            products = new ArrayList<Product>();
            products.add(new Product(1, "商品1"));
            products.add(new Product(2, "商品2"));

            redisTemplate.opsForValue().set("product:", products);
        } else {
            System.out.println("查詢緩存......");
        }
    }

    @Test
    public void delCacheTest() {
        redisTemplate.delete("product:");
    }

}

三、解決緩存穿透問題:

  原因:一個線程在訪問數據庫信息后還未寫入到緩存時丟失了時間片,其它線程訪問時重復訪問了數據庫,造成數據庫巨大壓力;

  解決:

    1)synchronized來加鎖:因為是分布式開發,synchronized的作用域是JVM,則在多個服務間synchronized是無效的;

    2)Redis分布式鎖:

      1、在redis本地使用:   

setnx Lock 1 //1
get Lock //1
setnx Lock 2 //00
del Lock
setnx Locks 2 //1

      2、springboot代碼實現:

        //try finally解決死鎖問題:

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedistestSpringData2ApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void multiThreadTest() throws InterruptedException {
        ExecutorService pool = new ThreadPoolExecutor(100, 200, 100, TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(100));
        for (int i = 0; i < 100; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    cacheTest();
                }
            });
        }
        Thread.sleep(1000000);
    }

    @Test
    public void cacheTest() {
        List<Product> products = (List<Product>) redisTemplate.opsForValue().get("product:");
        if (products == null) {
            Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent("product:lock", 1);
            if (ifAbsent) {
                try {
                    System.out.println("查詢數據庫......");
                    // 模擬從數據庫查詢數據
                    products = new ArrayList<Product>();
                    products.add(new Product(1, "商品1"));
                    products.add(new Product(2, "商品2"));
                    int i = 10 / 0;
                    redisTemplate.opsForValue().set("product:", products);
                } finally {
                    redisTemplate.delete("product:lock");
                }
            } else {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                cacheTest();
            }
        } else {
            System.out.println("查詢緩存......");
        }
    }

    @Test
    public void delCacheTest() {
        redisTemplate.delete("product:");
    }
}

四、解決緩存擊穿問題:

  原因:重復查詢為null時,每次都會重新訪問數據庫;

  解決:查詢到為null值時,返回一個空的對象給redis作為緩存,設置一定時間失效;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedistestSpringData2ApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    public Product productById(Integer id) {
        if (id > 10) {
            return null;
        }
        return new Product();
    }

    @Test
    public void cachePenetrationTest() {
        for (int i = 11; i < 20; i++) {
            Product product = (Product) redisTemplate.opsForValue().get("product:" + i);
            if (product == null) {
                // 模擬從數據庫查詢數據
                System.out.println("查詢數據庫......");
                // 如果i大於10,type都是null
                product = productById(i);
                // 如果時null返回一個空
                if (product == null) {
                    product = new Product(i, "");
                    redisTemplate.opsForValue().set("product:" + i, product);
                    redisTemplate.expire("product:" + i, 10, TimeUnit.MINUTES);
                } else {
                    redisTemplate.opsForValue().set("product:" + i, product);
                    redisTemplate.expire("product:" + i, 20, TimeUnit.MINUTES);
                }
            } else {
                System.out.println("查詢緩存......");
            }
        }
    }

    @Test
    public void delCacheTest() {
        redisTemplate.delete("product:");
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM