2021-07-13
时隔多日,再回首看缓存又有了不同的感悟
缓存应该本地缓存+redis分布式缓存搭建多级缓存
原因:无论如何本地缓存是最快的,之后才是redis,最后是不用缓存。
存在问题:缓存是存在上限的,如何在有限的空间内保证高速缓存?将高频次的缓存存在本地,采用一种淘汰策略保证存储数据既不会溢出又保证高效。如果本地缓存没有命中,则从分布式缓存中获取。如果分布式缓存依然没有获取则从数据库读取,获取到有效数据后存入本地和分布式缓存中,通过过期时间及淘汰策略保证缓存的高速有效。
最近试用spring boot cache 时发现如果项目中引入redis,会默认试用redis缓存,但是可以通过修改cacheType为Simple改为本地缓存
在使用本地缓存时发现一个小坑,不要修改获取的缓存数据,因为会直接修改缓存值,造成的结果可能是一个数值的不停修改;
2019-05-05 虽然已经换公司了,但是对缓存的理解还是写在这里
缓存:多用redis, 少用springboot自带的,因为redis可以分布式调用,扩展性比较好
java缓存原理:以一个获取机构logo的方法为例
//创建一个map作为缓存
private Map iconMap = new HashMap<>();
public String getOrgLogo(String orgId) {
if (StringUtils.isEmpty(orgId)) {
return "";
}
//从缓存中读取
String icon = iconMap.get(orgId);
if (StringUtils.isEmpty(icon)){
//没读到,从数据库获取
OrgDO orgDO = orgDao.get(orgId);
if (orgDO != null && !StringUtils.isEmpty(orgDO.getLogo())) {
//将读取的数据加入缓存
iconMap.put(orgId,orgDO.getLogo());
return orgDO.getLogo();
} else {
return "";
}
}else {
return icon;
}
}
需要清除缓存只需要一个iconMap.clear()即可
2018.10.17 由于网站用户访问量过大,开始优化性能
添加缓存
1.springboot 开启缓存: 在 @SpringBootApplication下添加@EnableCaching
2.在service 上添加@Cacheable("serviceName")
缓存机制:参数默认为缓存名,key为service方法中的参数。所以涉及分页问题时,需要在方法中传入当前页面的参数
清除缓存
service 上添加@CacheEvict(value = {"serviceName1","serviceName2","serviceName3"},allEntries = true)
如果修改数据,由于有缓存的存在,数据不会刷新,所以需要在修改数据的方法上添加清除缓存的注解;
参数value为需要清除的缓存名,allEntries表示将方法下的所有缓存全部清理
使用感受:添加缓存后,如果参数一致,则不进行service内的操作,直接返回上次的结果,项目的性能疯狂提升
使用静态资源服务器
将封面图等静态文件存入静态服务器上
之后通过http的方式来加载图片
存在问题:由于静态服务器上有缓存,导致重名文件无法正常加载。
自己完整开发的项目;感谢大神的帮助。。
项目搭建:
数据库设计
通过设计图简单总结了项目中会出现类基本来说全是类别与资源,二者之间是多对多的关系所以建立一个中间表就可以开始了
之后大神提点:如果可能,尽量把库拆分开来。。
但是个人觉得拆分后细节代码增多,整体思路变得复杂,不如将整个系统整体抽象来的简单;
当然目前数据量较小,时间紧可以这样做,未来考虑扩展性的话,还是拆分开来比较好
资源主要是和业务挂钩的实体
运用最多的是类别,而在一个表中管理多种类别,最好的方法就是添加父主键(pid)
idea创建springboot项目
主要思路:
1为了创建springboot下了jdk1.8
2选择最版本1.51,选择目录空间,名称,选择thymeleaf控件
3创建ok添加pom.xml 通过maven修改jdK,修改sprinboot引用
//修改jdk
UTF-8
UTF-8
1.7
3.0.8.RELEASE
2.2.2
//插件配置
src/main/java
**/*.xml
src/main/resources
org.apache.maven.plugins
maven-jar-plugin
3.0.2
com.schoolbag.SchoolbagApplication
true
lib/
./
ehcache.xml
**/xml/*.xml
**/*.class
templates/**
static/**
maven-assembly-plugin
3.1.0
false
./package.xml
make-assembly
package
single
4.关闭项目,将项目从工作空间移到git空间,通过git命令提交到gitlab上(通过.gitignore.xml可以不提交一些没用的文件)
5.自己别人可以从gitlab中获取代码
配置文件
核心 application.properties
#数据库 start
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/erya_new?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=
spring.datasource.password=r
#117.122.222.173
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.druid.async-init=true
#数据库 end
#thymeleaf start
spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML
#thymeleaf end
server.port=80
#编码
spring.http.encoding.force=true
#身份
spring.application.name=erya_new
#mybatis 路径配置
mybatis.mapper-locations=classpath*:/com/**/mapper/xml/*Mapper.xml
#静态路径
spring.web.upload-location=/opt/
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${spring.web.upload-location}
日志配置
%clr(%d{yyyy-MM-dd HH:mm:ss}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
${LOG_HOME}/${appName}-spring.log
${LOG_HOME}/${appName}-spring.%d{yyyy-MM-dd}.log
${LOG_MAX_HISTORY}
${FILE_LOG_PATTERN}
INFO
mybits_plus使用
下载jar包
按照介绍安装
最大的好处:1.生成实体,mapper,xml
2.mapper与xml可以互相跳转
安装后生成的xml很不好,大神给了jar让我替换
学到替换文件的技巧:
1将新文件拷入
2重命名源文件名,copy名字,之后追加.bak(备份文件)
3将新文件重命名原文件名
打包配置package.xml
存放与pom.xml平级,第一次运行巨慢。。
package
dir
false
src/main/resources
${file.separator}
*.xml
*.properties
${project.build.directory}
${file.separator}
*.jar
lib/
false
之后是项目的内部构成:
使用mybits-plus生成model,mapper,xml
bean目录下放自己组装的类
service下除了放mapper引用,还可以放api接口
controller可以分为移动端,pc端,还有API
util 存放常用的工具类,全局常量
html相关都放在resourses下面
mybits中的知识点
1.插入时主键如下声明,在mysql中如果是自增主键,在插入时主键可为空
2.多类别查询判断时,发现查询可以以查询为表如下
select * from (select * from t)
3.做并集和交集
left join t on 组合
inner join () 取交集
4.查询条件一个字段后面会有很多值
t.name in (a,b,c)
5.去重查询
select distinct x form t
js知识点
这个方法的可用性巨高无比
function getVal(s) {
if (s == null || s == undefined)
return ""
}
再说点大神给的建议,前端页面显示的静态图片最好统一放在一个img文件中,数据库只存文件名,这样每次改路径,存文件什么的比较方便,不用改很多
导入数据
由于是一个展示性的项目,所以资源数据巨多,用人力导是不现实的,总结下用poi导excel
导入时网上找的几个好用的方法
/**
* @Description 获取Sheet
* @date 2018-03-28
* @param file
* @return org.apache.poi.ss.usermodel.Sheet
*/
public static Sheet getSheet(File file,Integer page) throws IOException {
//获取输入流
final InputStream contactFileInputStream = new FileInputStream(file);
//获取book
Workbook workbook = null;
if (contactFileInputStream!=null) {
try {
workbook = WorkbookFactory.create(contactFileInputStream);
} catch (InvalidFormatException e) {
e.printStackTrace();
}
}
//获取sheet
Sheet sheet = null;
if (null != workbook) {
if (page == null){
sheet = workbook.getSheetAt(workbook.getActiveSheetIndex());
}else {
sheet = workbook.getSheetAt(page);
}
}
return sheet;
}
/**
* @Description 获取合并的单元格数据
* @date 2018-05-28
* @param sheet
* @param row
* @param column
* @return java.lang.String
*/
public static String getMergedRegionValue(Sheet sheet ,int row , int column){
int sheetMergeCount = sheet.getNumMergedRegions();
for(int i = 0 ; i < sheetMergeCount ; i++){
CellRangeAddress ca = sheet.getMergedRegion(i);
int firstColumn = ca.getFirstColumn();
int lastColumn = ca.getLastColumn();
int firstRow = ca.getFirstRow();
int lastRow = ca.getLastRow();
if(row >= firstRow && row <= lastRow){
if(column >= firstColumn && column <= lastColumn){
Row fRow = sheet.getRow(firstRow);
Cell fCell = fRow.getCell(firstColumn);
return getCellValue(fCell) ;
}
}
}
return null ;
}
/**
* 合并单元格处理,获取合并行
* @param sheet
* @return List
*/
public static List getCombineCell(Sheet sheet)
{
List list = new ArrayList<>();
//获得一个 sheet 中合并单元格的数量
int sheetmergerCount = sheet.getNumMergedRegions();
//遍历所有的合并单元格
for(int i = 0; i listCombineCell, Cell cell){
int xr = 0;
int firstC = 0;
int lastC = 0;
int firstR = 0;
int lastR = 0;
for(CellRangeAddress ca:listCombineCell)
{
//获得合并单元格的起始行, 结束行, 起始列, 结束列
firstC = ca.getFirstColumn();
lastC = ca.getLastColumn();
firstR = ca.getFirstRow();
lastR = ca.getLastRow();
if(cell.getRowIndex() >= firstR && cell.getRowIndex() <= lastR)
{
if(cell.getColumnIndex() >= firstC && cell.getColumnIndex() <= lastC)
{
xr = lastR;
}
}
}
return xr;
}
关于合并单元格的数据是个很大的坑
基本思想就是先判断是不是合并单元格,如果获取合并内容为null就不是合并单元格
如果是合并单元格,
new StringBuffer
遍历if(row==合并单元格行数 ){
set StringBuffer 和 合并单元格内的数据
}else {
string += 没有合并的数据
}
虽然也可以导word但是感觉,唯一的问题是每行都要看看他能不能在表中查到,肯定不靠谱。。so,看在只有40多条数据的份上用手导了。。
以上 1周项目总结