JAVA数据缓存之内存缓存
生活随笔
收集整理的這篇文章主要介紹了
JAVA数据缓存之内存缓存
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
JAVA數據緩存之內存緩存
簡要介紹
java內存緩存其實就是本地緩存 , 實現方法一般是從數據庫查詢出需要緩存的數據然后放到map里 ,根據需求可分為增量緩存和全量緩存,核心思想就是將想要查詢數據庫的用戶攔住,從內存緩存中拿到想要的數據返回給用戶。使用場景
1.前臺查詢用戶量比較大, 一直去查數據庫會對數據庫造成壓力。 2.數據量比較大 從大數據量里邊拿一小部分數據,一般是一個人的相關數據。 3.非集群環境 集群環境使用內存緩存會使內存的使用量變化過大,集群環境數據量不是特別大推薦redis數據緩存 ,數據量過大使用mogoDB緩存。4.數據量特別大不建議使用,過度使用內存存儲會對服務器造成壓力。5.緩存之前一定得試一下你那個查詢到底多少秒能查出來,如果查詢都很慢,然后你又要求數據緩存做成實時的(比如一秒一刷)這樣會造成線程隊列堆積,這樣會把服務直接刷死。特性
1.直接使用JAVA內存緩存查詢速度是比redis快的。2.不能持久化(mogoDB和redis可以持久化)。數據緩存前期準備
數據緩存最不可或缺的步驟為定時任務,這里我們使用的是spring提供的定時任務 ,配合cron表達式實現定時刷新緩存, 真正的線上環境絕對不是只緩存一種數據,所以定時任務一定得是多線程的,不能為串行執行,所以需要進行如下配置。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.concurrent.Executor; import java.util.concurrent.Executors;/*** 沒有此配置,則schedule為單線程串行執行*/ @Configuration @EnableScheduling public class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(taskExecutor());}//配置線程池---觸發器和任務共用的@Bean(destroyMethod="shutdown")public Executor taskExecutor() {return Executors.newScheduledThreadPool(10);} }初始化數據
使用數據緩存之前首先需要初始化好裝數據的map和記錄增量緩存的緩存時刻(寫增量緩存的話是需要記錄上一次緩存的時間,在這個時間之后的數據需要進行緩存),這兩種數據都寫成全局變量也就是定義在類里邊方法上邊。 //因為要使用增量緩存 首先初始化用到的時間private Timestamp firmDataTime = null;//初始化hashMap用來存儲緩存值public static ConcurrentHashMap<Integer , Firm> firmData = new ConcurrentHashMap<>();全量緩存使用場景
數據在一定時間內是不變的,或者在特定的時間進行改變然后一定時間內不改變(比如市場結算時候的分成數據,市場會在每天閉市后進行結算分成,意思是這個數據會在每天閉市后生成,并在下一次閉市前保持不變)全量緩存代碼塊簡要解釋
從1號開始每天進行一次全量緩存 首先清理緩存,然后查數據庫,然后把數據庫的數據裝到map里邊,邏輯是比較簡單的。全量緩存代碼展示
//全量緩存@Scheduled(cron = "0 0 0 1/1 * ? ")public void cacheAllFirm(){firmData = null;List<Firm> firms = firmRepo.findAll();ConcurrentHashMap<Integer , Firm> allFirmMap= new ConcurrentHashMap<>();for(Firm firm : firms){allFirmMap.put(firm.getFirmId() , firm);}firmData = allFirmMap;}增量緩存使用場景
一般其實做數據緩存的話是使用增量緩存,核心思想就是只緩存修改或新增的數據,緩存的數據少了,自然速度就快了。增量緩存代碼塊簡要解釋
這里寫的是一個每三秒進行一次增量緩存,首先記錄一下當前時間,然后減去一個緩沖時間(意思就是每次增量緩存需要多緩存一些,防止因為任務的執行或者數據的變動少緩存數據,這個緩沖時間一般設置成2秒3秒左右,不用擔心會多緩存數據,因為map 的存儲特性key是唯一的,不會重復存儲)如果map是空的首先就得進行一次全量緩存,不為空才增量 只查詢記錄緩存時間之后的數據,并put到map里,每次裝完數據記錄一個時間。增量緩存代碼展示
@Scheduled(cron = "*/3 * * * * ? ")public void cacheFirm(){log.info("每三秒增量緩存一次firm");Long time = new Timestamp(System.currentTimeMillis()).getTime() - 3000;if(firmData.isEmpty()){List<Firm> v = firmRepo.findAll();//第一次緩存先全量緩存一次log.info("全量緩存開始");addDateFirm(v , time);}else{List<Firm> v = firmRepo.findAllByUpdateTimeAfterOrCreateTimeAfter(firmDataTime , firmDataTime);//進行增量緩存log.info("增量緩存開始");addDateFirm(v , time);}}private void addDateFirm(List<Firm> firms , Long time){if(firms != null && firms.size() > 0 ){for(Firm firm : firms){firmData.put(firm.getFirmId() , firm);}}firmDataTime = new Timestamp(time);}以下是內存緩存的全部測試代碼(包括以上舉的例子)
controller
import com.tjdami.zs.test.jpa.model.Firm; import com.tjdami.zs.test.service.TestService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/*** @Auther: Zyy* @Date: 2020/12/7 10:34* @Description:*/ @Api(value = "測試服務", description = "通用測試服務") @RequestMapping("/test") @RestController @Slf4j public class TestController {@Autowiredprivate TestService testService;@RequestMapping(value = "/cacheFirm")@ApiOperation(value = "查看客戶信息", httpMethod = "POST", notes = "查看客戶信息")public Firm distribute(@RequestHeader("firmId") String firmId) throws Exception {return testService.getFirmCache(Integer.valueOf(firmId));}}service
import com.tjdami.zs.test.cache.TextCache; import com.tjdami.zs.test.jpa.model.Firm; import org.springframework.stereotype.Service;/*** @Auther: Zyy* @Date: 2020/12/7 11:02* @Description:*/ @Service public class TestService {public Firm getFirmCache(Integer firmId) throws Exception {Firm firm = TextCache.firmData.get(firmId);return firm;} }緩存核心
import com.tjdami.zs.test.jpa.model.Firm; import com.tjdami.zs.test.jpa.repo.FirmRepo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap;/*** @Auther: Zyy* @Date: 2020/12/7 11:17* @Description:*/ @Component @Slf4j public class TextCache {@Autowiredprivate FirmRepo firmRepo;//因為要使用增量緩存 首先初始化用到的時間private Timestamp firmDataTime = null;private Timestamp firmDataListTime = null;//初始化hashMap用來存儲緩存值public static ConcurrentHashMap<Integer , Firm> firmData = new ConcurrentHashMap<>();//初始化一個存儲firm集合的map集合public static ConcurrentHashMap<Integer , List<Firm>> firmDataList = new ConcurrentHashMap<>();@Scheduled(cron = "*/3 * * * * ? ")public void cacheFirm(){log.info("每三秒增量緩存一次firm");Long time = new Timestamp(System.currentTimeMillis()).getTime() - 3000;if(firmData.isEmpty()){List<Firm> v = firmRepo.findAll();//第一次緩存先全量緩存一次log.info("全量緩存開始");addDateFirm(v , time);}else{List<Firm> v = firmRepo.findAllByUpdateTimeAfterOrCreateTimeAfter(firmDataTime , firmDataTime);//進行增量緩存log.info("增量緩存開始");addDateFirm(v , time);}}private void addDateFirm(List<Firm> firms , Long time){if(firms != null && firms.size() > 0 ){for(Firm firm : firms){firmData.put(firm.getFirmId() , firm);}}firmDataTime = new Timestamp(time);}//全量緩存@Scheduled(cron = "0 0 0 1/1 * ? ")public void cacheAllFirm(){firmData = null;List<Firm> firms = firmRepo.findAll();ConcurrentHashMap<Integer , Firm> allFirmMap= new ConcurrentHashMap<>();for(Firm firm : firms){allFirmMap.put(firm.getFirmId() , firm);}firmData = allFirmMap;} }定時任務多線程配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.concurrent.Executor; import java.util.concurrent.Executors;/*** 沒有此配置,則schedule為單線程串行執行*/ @Configuration @EnableScheduling public class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(taskExecutor());}//配置線程池---觸發器和任務共用的@Bean(destroyMethod="shutdown")public Executor taskExecutor() {return Executors.newScheduledThreadPool(10);} }實體類
import lombok.Data; import lombok.experimental.Accessors;import javax.persistence.*; import java.io.Serializable;@Data @Entity @Table(name = "firm") public class Firm implements Serializable {@Id@GeneratedValue@Column(name = "firm_id")private Integer firmId;@Column(name = "firm_name")private String firmName;@Column(name = "create_time", insertable = false, updatable = false)private java.sql.Timestamp createTime;@Column(name = "update_time", insertable = false, updatable = false)private java.sql.Timestamp updateTime;}JPA
import com.tjdami.zs.test.jpa.model.Firm; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query;import java.sql.Timestamp; import java.util.List; import java.util.Map;public interface FirmRepo extends JpaRepository<Firm, Integer>, JpaSpecificationExecutor<Firm> {List<Firm> findAllByUpdateTimeAfterOrCreateTimeAfter(Timestamp timea , Timestamp timeb);}以上就是本期的全部內容了,操作數據庫的技術為JPA加哈伯奈特,換成mybatis或者jdbc也是一樣的簡單哦,如果大家覺得有幫助一定記得動動小手點個贊。
總結
以上是生活随笔為你收集整理的JAVA数据缓存之内存缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华强北三代悦虎1562A怎么样?
- 下一篇: iOS数据持久化