DataSource的缓存(基于时间最大值v1)

最近做一个根据前端的url,username,password,sql的信息创建数据源进而获得Connection进行JDBC操作sql。
Connection缓存已经使用数据库连接池实现了,想把DataSource缓存起来,不用每次进来都创建数据源。

一、理论:
1.FIFO(First Input First Output):
特点:先进先出,符合公平性,实现简单。

数据结构:使用对列

淘汰原则:如果一个数据最先进入缓存中,则应该最早淘汰掉。也就是说,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉。

2.LRU(Least Recently Used):
特点:按照时间长短,最不经常使用的缓存数据,先淘汰。

数据结构:链表和hashmap

淘汰原则:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。

3.LFU(Least Frequently Used):
特点:按照访问次数,最近最少使用的缓存数据,先淘汰。

数据结构:数组、hashmap、堆

淘汰原则:如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。

https://blog.csdn.net/zhaoyunfullmetal/article/details/48497499
https://blog.csdn.net/u013314786/article/details/80658738

https://blog.csdn.net/zhengzhaoyang122/article/details/82184029


import javax.sql.DataSource;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Title: Memory
 * @ProjectName database
 * @Description: 数据源缓存
 * @Author wangben
 * @Date 2019/7/2- 14:48
 */
public class DataSourceCache {

    /**
     * 缓存最大个数
     */
    private static final Integer CACHE_MAX_NUMBER = 5;
    /**
     * 当前缓存个数
     */
     public static  Integer CURRENT_SIZE = 0;

    /**
     * 这个记录了缓存使用的最后一次的记录,最近使用的在最前面
     */
    private static final List<String> CACHE_USE_LOG_LIST = new LinkedList<>();
    /**
     * 键值对集合
     */
    private final static Map<String, Entity> map = new HashMap<>(5);
    /**
     * 定时器线程池,用于清除过期缓存
     */
    private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    /**
     * 添加缓存
     *
     * @param key  键
     * @param data 值
     */
    public synchronized static void put(String key, DataSource data) {
        DataSourceCache.put(key, data, 0);
    }

    /**
     * 添加缓存
     *
     * @param key    键
     * @param data   值
     * @param expire 过期时间,单位:毫秒, 0表示无限长
     */
    public synchronized static void put(String key, DataSource data, long expire) {
        //清除原键值对
        DataSourceCache.remove(key);
        //判断缓存数量是否超过容量
        checkSize();
        //将key缓存到linkedlist里
        saveCacheUseLog(key);
        //设置过期时间
        if (expire > 0) {
            Future future = executor.schedule(new Runnable() {
                @Override
                public void run() {
                    //过期后清除该键值对
                    synchronized (DataSourceCache.class) {
                        map.remove(key);
                    }
                }
            }, expire, TimeUnit.MILLISECONDS);
            map.put(key, new Entity(data, future));
        } else {
            //不设置过期时间
            map.put(key, new Entity(data, null));
        }
        //缓存数量+1;
        CURRENT_SIZE = CURRENT_SIZE + 1;

    }

    /**
     * 读取缓存
     *
     * @param key 键
     * @return
     */
    public  static <T> T get(String key) {
        Entity entity = map.get(key);
        return entity == null ? null : (T) entity.getDataSource();
    }

    /**
     * 清除缓存
     *
     * @param key 键
     * @return
     */
    public synchronized static <T> T remove(String key) {
        //清除原缓存数据
        Entity entity = map.remove(key);
        if (entity == null) {
            return null;
        }
        //清除原键值对定时器
        if (entity.future != null) {
            entity.future.cancel(true);
        }
        CURRENT_SIZE = CURRENT_SIZE - 1;
        return (T) entity.getDataSource();
    }

    private static  class Entity {
        /**
         * 键值对的value
         */
        public DataSource dataSource;
        /**
         * 定时器Future
         */
        public Future future;

        public DataSource getDataSource() {
            return dataSource;
        }


        public Entity(DataSource dataSource, Future future) {
            this.dataSource = dataSource;
            this.future = future;
        }
    }




    /**
     * 判断缓存在不在
     */
    private static boolean checkCache(String cacheKey) {
        Entity cacheObj = map.get(cacheKey);
        if (cacheObj == null) {
            return false;
        }
        return true;
    }
    /**
     * 删除最近最久未使用的缓存
     */
    private static void deleteLRU() {
        String cacheKey = null;
        synchronized (CACHE_USE_LOG_LIST) {
            if (CACHE_USE_LOG_LIST.size() >= CACHE_MAX_NUMBER ) {
                cacheKey = CACHE_USE_LOG_LIST.remove(CACHE_USE_LOG_LIST.size() - 1);
            }
        }
        if (cacheKey != null) {
            remove(cacheKey);
        }
    }
    /**
     * 保存缓存的使用记录
     */
    private static synchronized void saveCacheUseLog(String cacheKey) {
        synchronized (CACHE_USE_LOG_LIST) {
            CACHE_USE_LOG_LIST.remove(cacheKey);
            CACHE_USE_LOG_LIST.add(0,cacheKey);
        }
    }

    /**
     * 检查大小
     * 当当前大小如果已经达到最大大小
     * 首先删除过期缓存,如果过期缓存删除过后还是达到最大缓存数目
     * 删除最久未使用缓存
     */
    private static void checkSize() {
        if (CURRENT_SIZE >= CACHE_MAX_NUMBER) {
            deleteLRU();
        }
    }


}
package com.wang.database.db.jdbc;

import com.wang.database.db.config.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Title: DbJdbcUtil
 * @ProjectName demo
 * @Description: 对外提供接口,用于获取数据源,执行sql
 * @Author wangben
 * @Date 2019/7/1- 11:00
 */
@Slf4j
@Service
@PropertySource("classpath:jdbc.properties")
public class DbJdbcUtil extends ConnectionManager{


    @Autowired
    private MysqlConfig mysqlConfig;

    @Autowired
    private PostgresqlConfig postgresqlConfig;

    @Autowired
    private OracleConfig oracleConfig;

//    @Value("${mysql.datasource.driverClassName}")
//    String mysqlDriver;
//
//    @Value("${oracle.datasource.driverClassName}")
//    String oracleDriver;
//
//    @Value("${postgresql.datasource.driverClassName}")
//    String postgresqlDriver;


    /** @Description 判断数据库类型,并获得数据源
     * @param url :
     * @param username :
     * @param password :
     * @return javax.sql.DataSource
     * @throws
     * @Author wangben
     * @Date 2019/7/2 14:00
     */
    public  DataSource optDataSource(String url,String username, String password){
        log.info("DButils optDataSource begin");
        DataSource dataSource=null;
        JdbcProperties jdbcProperties=null;
        /*String mysqlDriver="com.mysql.cj.jdbc.Driver";
        String oracleDriver="oracle.jdbc.OracleDriver";
        String postgresqlDriver="org.postgresql.Driver";*/
        try {
            if(url==null&&url.length()==0){
                log.error("Url is null");
                return null;
            }else {
                String[] split = url.split(":");
                jdbcProperties = new JdbcProperties(url,null, username, password);
                String dbType = split[1];
                //去缓存查找
                dataSource = getDataSourceByCache(jdbcProperties, dbType);
            }
        }catch (Exception e){
            log.error("DbJdbcUtil optDataSource error");
        }
        log.info("DButils optDataSource end");
        return dataSource;
    }
    /** @Description 根据数据库连接的相关信息获取缓存里的数据源,没有则添加数据源到缓存。
     * 相关设置:数据源过期时间,等待超时时间,测试数据源连接是否正常。
     * @return javax.sql.DataSource
     * @throws
     * @Author wangben
     * @Date 2019/7/2 14:16
     */
    public DataSource getDataSourceByCache(JdbcProperties jdbcProperties,String dbType){
        log.info("getDataSourceByCache begin");
        //先去缓存查找
        DataSource dataSource = DataSourceCache.get(jdbcProperties.toString());
        System.out.println(dataSource);
        if(dataSource==null){
            //找不到,创建数据源,并添加到缓存
            log.info("Get cache error");
            switch(dbType){
                case "mysql" :
                    dataSource = mysqlConfig.mysqlDataSource(jdbcProperties);
                    break;
                case "postgresql" :
                    dataSource = postgresqlConfig.postgresqlDataSource(jdbcProperties);
                    break;
                case "oracle" :
                    dataSource = oracleConfig.oracleDataSource(jdbcProperties);
                    break;
                default :
                    log.error("DbType is error");
            }
            //添加到缓存
            DataSourceCache.put(jdbcProperties.toString(), dataSource);
            log.info("Add Cache end");
        }else {
            log.info("Get success from the cache");
        }
        log.info("Cache size is "+DataSourceCache.CURRENT_SIZE);
        return dataSource;
    }


    /** @Description 执行增删改sql
     * @param dataSource :
     * @param sql :
     * @param params :
     * @return boolean
     * @throws
     * @Author wangben
     * @Date 2019/7/2 13:59
     */
    public  boolean executeSQL(DataSource dataSource ,String sql, String... params) {
        log.info("DButils executeSQL begin");
        boolean flag = false;
        PreparedStatement statement = null;
        try {
            Connection connection = getConnection(dataSource);
            log.info("DButils executeSQL getConnection end");
            statement = connection.prepareStatement(sql);
            log.info("DButils executeSQL getStatement end");
            for (int i = 0, n = params.length; i < n; i++) {
                statement.setString(i + 1, params[i]);
            }
            statement.execute();
            log.info("DButils executeSQL statement execute end");
            flag = true;
        } catch (SQLException e) {
            log.error("DButils executeSQL ----",e);
        } finally {
            closeStatement(statement);
            closeConnection();
        }
        log.info("DButils executeSQL end");
        return flag;
    }


    /** @Description 执行查询sql返回List
     * @param dataSource :
     * @param sql :
     * @return java.util.List
     * @Author wangben
     * @Date 2019/7/2 13:59
     */
    public  List queryListBySql(DataSource dataSource, String sql) {
        log.info("DButils queryListBySql begin");
        ResultSet resultSet = null;
        PreparedStatement statement = null;
        List rlist=new ArrayList();
        try {
            Connection connection = getConnection(dataSource);
            log.info("DButils queryListBySql getConnection end");
            statement = connection.prepareStatement(sql);
            log.info("DButils queryListBySql getStatement end");
            resultSet = statement.executeQuery();
            log.info("DButils queryListBySql getResultSet end");
            if (resultSet != null) {
                ResultSetMetaData rsm = statement.getMetaData();
                int columnsum=rsm.getColumnCount();
                while (resultSet.next()) {
                    Map senmap=new HashMap();
                    for (int i=0;i<columnsum;i++){
                        senmap.put(rsm.getColumnName(i+1),resultSet.getObject(i+1)==null?"":resultSet.getObject(i+1).toString());
                    }
                    rlist.add(senmap);
                }
            }
        } catch (SQLException e) {
            log.error("DButils queryListBySql error",e);
            return null;
        }finally {
            closeResultSet(resultSet);
            closeStatement(statement);
            closeConnection();
        }
        log.info("DButils queryListBySql end");
        return rlist;
    }
}

更简单的实现:https://blog.csdn.net/zxd8080666/article/details/79614050
补充:高并发下System.currentTimeMillis()并发问题以及优化对比 https://blog.csdn.net/qq_38011415/article/details/82813299

2019年7月16日11:39:57

//用于缓冲数据Map
public static HashMap cacheMap = new HashMap<String, DataSource>();
//时间key
public final static String TIME_KEY = “cateTime”;
//数据key
private final static String DATE_KEY = “cateList”;
//缓冲时间1小时
public final static long EXPIRATIONTIME = 1000 * 10;

if(jdbcProperties.toString(()+“time”,时间== null || !cacheMap.containsKey(dataKey)){
return false;
}
Long expiryTime = (Long) cacheMap.get(aa);
//如果当前时间大于缓存过期时间就移除map里的数据key
if (SystemClock.millisClock().now() > expiryTime.longValue()) {
cacheMap.remove(dataKey);
return false;
}


import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @Title: SystemClock
 * @ProjectName database
 * @Description:
 *  * 高并发场景下System.currentTimeMillis()的性能问题的优化
 *  * 时间戳打印建议使用
 *  * 调用示例
 *  * Long start = SystemClock.millisClock().now()
 *
 * @Author wangben
 * @Date 2019/7/3- 10:10
 */

public class SystemClock {
    private static final String THREAD_NAME = "system.clock";
    private static final SystemClock MILLIS_CLOCK = new SystemClock(1);
    private final long precision;
    private final AtomicLong now;

    private SystemClock(long precision) {
        this.precision = precision;
        now = new AtomicLong(System.currentTimeMillis());
        scheduleClockUpdating();
    }

    public static SystemClock millisClock() {
        return MILLIS_CLOCK;
    }

    private void scheduleClockUpdating() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
            Thread thread = new Thread(runnable, THREAD_NAME);
            thread.setDaemon(true);
            return thread;
        });
        scheduler.scheduleAtFixedRate(() ->
                now.set(System.currentTimeMillis()), precision, precision, TimeUnit.MILLISECONDS);
    }

    public long now() {
        return now.get();
    }
}


        if(DataSourceCache.isInvalid(jdbcProperties.toString()+DataSourceCache.TIME_KEY,jdbcProperties.toString())){
            //存活时间内去查找缓存
            dataSource = (DataSource) DataSourceCache.cacheMap.get(jdbcProperties.toString());
            //更新缓存时间
            DataSourceCache.cacheMap.put(jdbcProperties.toString()+DataSourceCache.TIME_KEY, SystemClock.millisClock().now() + DataSourceCache.EXPIRATIONTIME);
        }
//找不到
 //将查出来的数据放入map
DataSourceCache.cacheMap.put(jdbcProperties.toString(), dataSources);
//设置缓存时间
DataSourceCache.cacheMap.put(jdbcProperties.toString()+DataSourceCache.TIME_KEY, SystemClock.millisClock().now() + DataSourceCache.EXPIRATIONTIME);

用两个map更好,amap(key+标记值,时间);
bmap(key,value);
先根据bmap的过滤掉不存在的key,然后通过key+标记值判断时间是否超期。都通过则拿到value,否则去查,然后添加a,bmap;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值