一、根本概念
缓存池机制主要用于存储和管理经常访问的数据,以进步应用的性能和相应速率。它通过将计算的数据或着将数据库查询的效果缓存起来,淘汰重复计算和数据重新获取,从而进步效率。
1. 根本概念
缓存池是一种临时存储空间,用于生存数据的副本,这些副本可以是计算效果、数据库查询效果或其他必要频繁访问的数据。当必要数据时,起首检查缓存,如果缓存中存在,则直接使用;否则,从原始数据源获取并将其存入缓存。
2. 缓存的类型
- 内存缓存:数据存储在应用步伐的内存中,速率快,但受限于可用内存。
- 分布式缓存:数据存储在多个节点上,适用于大规模系统,如Redis。
3. 使用思量:
- 缓存失效计谋:① 设置超时失效时间;② 限制缓存最大容量,到达限制时,可采取LRU、LFU等计谋镌汰旧数据;③ 根据特定条件(如数据更新)主动扫除缓存。
- 缓存数据与源数据的同等性
- 多线程数据的同等性
4. 缓存池与进程、线程的关系
4.1 进程中的缓存池:
- 隔离性:差别进程相互隔离,如需跨进程共享缓存池,需使用共享内存或外部服务实现数据共享。
- 资源竞争:多个进程同时访问共享资源时,可能会导致资源竞争,必要使用同步机制(互斥锁)管理。
4.2 线程中的缓存池:
- 共享性:同一进程的线程可以共享资源池,一个线程修改缓存内容会对其他线程造成影响。
- 线程安全:多个线程可以同时访问/修改缓存池,因此必要保证线程安全,可以使用synchronized关键字或其他并发工具进行同步。
- 性能题目:高并发环境下,过多同步可能会导致性能瓶颈。为了进步性能,可以思量使用并发聚集(ConcurrentHashMap)或计划无锁算法。
数据库连接池是用来管理数据库连接的工具,尤其对于高并发的环境,使用连接池可以避免频繁创建和关闭数据库连接,淘汰资源斲丧。
1. 根本概念
- 数据库连接:每次应用步伐与数据库交互时,都必要创建一个连接。这一过程往往开销较大,涉及网络通信、身份验证等。
- 连接池:连接池是一组预先创建好的数据库连接,这些连接可以被多个客户端共享,避免频繁的连接和断开。
2. 工作原理
- 初始化:当应用步伐启动时,连接池会创建一定命量的数据库连接并保持在池中,等待请求。
- 获取连接:当应用步伐必要访问数据库时,它会从连接池中获取一个可用的连接,而不是新建一个连接。
- 开释连接:使用完毕后,连接不会被关闭,而是返回连接池,以便其他请求重用。
- 管理连接:连接池会定期检查连接的有效性,主动关闭失效的连接,并根据必要创建新的连接以维持池的巨细。
3. 常见参数配置:
- 最大/最小连接数:连接池中的最大/最小连接数量
- 连接超时时间:连接申请的最大等待时间
- 空闲连接超时时间:连接在池中空闲的最大时间
- 最大等待实现:当连接池已满时,申请连接的最大等待时间
二、代码实现
1. 场景形貌:
1. 场景形貌:
现有一个主系统,该主系统下有多个子系统,主系统可以连接所有子系统的数据库(主系统的数据表base_datasource中存着所有子系统的数据库信息),查询这些子系统的用户信息(用户信息表:base_person)。
2. 实现以下功能:
主系统步伐要连接某个子系统的数据库查询用户信息,步伐先从缓存池中获取数据库信息,如果缓存池中没有,则从数据库中查询该子系统的数据库信息,创建一个连接池,将其添加到缓存池中,最后连接该数据库查询数据。
2. 该功能的实现用到的工具类
2.1 ConcurrentHashMap(缓存池)
ConcurrentHashMap是Java中用于高效并发访问的哈希表实现,它允许多个线程同时读取和写入数据,而不会导致数据差别等或性能瓶颈。
1. 根本概念:
- 线程安全:ConcurrentHashMap是线程安全的,可以在多个线程中安全使用。
- 分段锁:它采取分段锁的机制,将数据分为多个段,每个段都有独立的锁,这样可以淘汰锁竞争,进步并发性能。
2. 主要特性:
- 高效性:相比于其他同步聚集(HashTable),ConcurrentHashMap提供更高的并发性能,尤其在读操作频繁的场景下。
- 非阻塞读:读取操作不会被写入操作阻塞,只有当修改某个特定段时,才会对该段加锁。
- 弱同等性:在遍历时可能会看到一些"瞬态"值,即在遍历期间更新的数据。
3. 使用场景:
- 高并发环境:适合多线程环境中必要频繁读取和写入的场景,如缓存、计数器等。
- 共享数据:在多个线程共享数据时,ConcurrentHashMap可以避免复杂的同步机制。
2.2 DruidDataSource(数据库连接池)
DruidDataSource是阿里巴巴开源的一个高性能、可扩展的数据库连接池,他是Druid项目标一部门。Druid提供了一个丰富的功能,特殊适适用于生产环境中的Java应用步伐。
1. 根本特性:
- 高性能:Druid提供了高效的数据库连接管理,可以或许处理大量的连接请求。
- 监控功能:内置了监控和统计功能,可以对数据库连接的使用环境进行实时监控。
- SQL解析:支持SQL的解析和审计功能,可以记录SQL实行的具体环境。
2. 配置:
Druid的配置非常灵活,可以通过XML、properties文件或Java代码进行配置,常见配置包罗:
- 连接池巨细:设置初始连接数、最大连接数等。
- 连接超时时间:设置获取连接的最大等待时间。
- 验证查询:可以配置在获取连接时实行的SQL语句,以检查连接是否有效。
3. 监控与管理:
- Druid提供了Web界面,可以通过访问特定的URL进行连接池的监控和管理,例如检察当前连接数量、活动连接、SQL实行统计等。
- 也可以通过JMX(Java Management Extensions)来监控连接池的状态。
4. 安全性
Druid提供了一些安全特性,比如SQL防注入、优劣名单等。
2.3 SqlSessionFactory (管理数据库连接和会话)
SqlSessionFactory是MyBatis框架中用于创建SqlSessiobn的工厂接口。它是MyBatis的核心组件之一,负责管理数据库连接和会话的配置。
1. 根本概念
- SqlSession:代表与数据库的一个会话,用于实行Sql语句、获取映射器等。
- SqlSessionFactory:用来创建SqlSession,通常在应用启动时创建一次并在整个应用生命周期中重用。
2. 创建SqlSessionFactory
SqlSessionFactory的创建通常通过读取MyBatis的配置文件来实现。可以通过SqlSessionFactoryBuilder来构建它。
3. mybatis-config.xml的配置:
- 数据源:设置数据库连接池的信息(如JDBC URL、用户名、密码等)。
- 映射器:指定映射器XML文件或注解的路径。
- 插件:可以配置MyBatis插件,用于扩展功能。
4. 线程安全:
SqlSessionFactory是线程安全的,可以在应用中共享,每个线程应该自己创建SqlSession实例,而不是共享SqlSession对象。
5. 常见题目:
- 事务管理:确保在操作完成后精确提交和回滚事务,以保证数据的同等性。
- 性能优化:公道配置缓存和映射器,来优化性能。
2.4 Mapper (定义数据库操作)
Mapper是MyBatis的紧张构成部门,它用于定义数据库操作的方法并将这些方法与SQL语句映射。
3. 代码实现
3.1 添加依赖:
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.2.9</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.5.13</version>
- </dependency>
复制代码 3.2 配置文件配置主数据库信息
- #oracle
- spring.datasource.dynamic.primary=anita
- spring.datasource.dynamic.datasource.anita.url=jdbc:oracle:thin:@oracle_url
- spring.datasource.dynamic.datasource.anita.driver-class-name=oracle.jdbc.OracleDriver
- spring.datasource.dynamic.datasource.anita.username=anita
- spring.datasource.dynamic.datasource.anita.password=anitazxq
复制代码 3.3 定义实体类
3.3.1 base_datasource实体类:DataSourceModel
- package com.example.dataSource.dto;
- import com.baomidou.mybatisplus.annotation.TableName;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("base_datasource")
- public class DataSourceModel {
- private String id;
- private String dbname;
- private String dbuser;
- private String dbpassword;
- private String dburl;
- private String dbdriver;
- }
复制代码 3.3.2 base_person的实体类:BasePersonModel
- package com.example.dataSource.dto;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class BasePersonModel {
- private String id;
- private String name;
- }
复制代码 3.4 定义Mapper
3.4.1 DataSourceModel对应的Mapper:DataSourceMapper
- package com.example.dataSource.mapper;
- import com.baomidou.dynamic.datasource.annotation.DS;
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.example.dataSource.dto.DataSourceModel;
- import org.apache.ibatis.annotations.Mapper;
- @Mapper
- @DS("anita") //指定数据源
- public interface DataSourceMapper extends BaseMapper<DataSourceModel> {
- }
复制代码 3.4.2 BasePersonModel 对应的Mapper:BasePersonMapper
- package com.example.dataSource.mapper;
- import com.example.dataSource.dto.BasePersonModel;
- import org.apache.ibatis.annotations.Select;
- import java.util.List;
- public interface BasePersonMapper {
- @Select("SELECT * FROM base_person")
- List<BasePersonModel> getAllData();
- }
复制代码 3.5 定义Service层
根据dbName查询数据库连接信息
- package com.example.dataSource.service;
- import com.alibaba.druid.pool.DruidDataSource;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.example.dataSource.dto.BasePersonModel;
- import com.example.dataSource.dto.DataSourceModel;
- import com.example.dataSource.mapper.BasePersonMapper;
- import com.example.dataSource.mapper.DataSourceMapper;
- import com.example.dataSource.utils.DataSourceCacheUtil;
- import com.example.dataSource.utils.MyBatisUtil;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.List;
- @Service
- public class DataOperateService {
- @Autowired
- private DataSourceMapper dataSourceMapper;
- //根据数据源名称查询数据库信息
- public DataSourceModel getDataSourceByDbName(String dbName)
- {
- QueryWrapper<DataSourceModel> queryWrapper=new QueryWrapper<>();
- queryWrapper.eq("dbname",dbName);
- DataSourceModel dataSource=dataSourceMapper.selectOne(queryWrapper);
- return dataSource;
- }
- }
复制代码 3.6 数据库连接池
- package com.example.dataSource.utils;
- import com.alibaba.druid.pool.DruidDataSource;
- import com.example.dataSource.dto.DataSourceModel;
- import org.springframework.stereotype.Component;
- @Component
- public class DataSourceConnectionUtil {
- //创建数据库连接池
- public static DruidDataSource createDataSource(DataSourceModel dataSourceModel)
- {
- DruidDataSource dataSource=new DruidDataSource();
- dataSource.setDriverClassName(dataSourceModel.getDbdriver());
- dataSource.setUrl(dataSourceModel.getDburl());
- dataSource.setUsername(dataSourceModel.getDbuser());
- dataSource.setPassword(dataSourceModel.getDbpassword());
- dataSource.setValidationQuery("SELECT 1 FROM DUAL");//ORACLE验证查询
- dataSource.setTestWhileIdle(true);
- dataSource.setTestWhileIdle(false);
- dataSource.setTestOnReturn(false);
- //避免连接数一直增加
- dataSource.setKeepAlive(false);
- //设置keepAlive的时间间隔,单位毫秒
- dataSource.setKeepAliveBetweenTimeMillis(60000);
- dataSource.setTimeBetweenEvictionRunsMillis(50000);
- dataSource.setMinEvictableIdleTimeMillis(300000);
- dataSource.setMaxEvictableIdleTimeMillis(480000);
- dataSource.setBreakAfterAcquireFailure(true);
- dataSource.setConnectionErrorRetryAttempts(1);
- dataSource.setMinIdle(5);
- dataSource.setMaxActive(200);
- dataSource.setMaxWait(30000);
- return dataSource;
- }
- }
复制代码 3.7 缓存池
- package com.example.dataSource.utils;
- import com.alibaba.druid.pool.DruidDataSource;
- import com.example.dataSource.dto.DataSourceModel;
- import com.example.dataSource.service.DataOperateService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import java.util.concurrent.ConcurrentHashMap;
- @Component
- public class DataSourceCacheUtil {
- @Autowired
- private DataOperateService dataOperateService;
- @Autowired
- private DataSourceConnectionUtil dataSourceConnectionUtil;
- private static final ConcurrentHashMap<String, DruidDataSource> dataSourceCache=new ConcurrentHashMap<>();
- //获取数据库连接
- public DruidDataSource getDataSource(String dbName)
- {
- //从缓存池中获取数据库信息
- DruidDataSource dataSource=dataSourceCache.get(dbName);
- if(dataSource==null)
- {
- DataSourceModel ds=dataOperateService.getDataSourceByDbName(dbName);
- //创建数据库连接池
- dataSource=dataSourceConnectionUtil.createDataSource(ds);
- }
- dataSourceCache.put(dbName,dataSource);
- return dataSource;
- }
- //在应用结束时关闭数据库连接池
- public void close()
- {
- for(DruidDataSource dataSource : dataSourceCache.values())
- {
- dataSource.close();
- }
- }
- }
复制代码 3.8 创建SqlSessionFactory
初始化 MyBatis 所需的配置,并预备好一个可以用于数据库操作的 SqlSessionFactory 实例。通过这个工厂,应用步伐可以方便地获取 SqlSession,从而进行数据库操作。
- package com.example.dataSource.utils;
- import com.alibaba.druid.pool.DruidDataSource;
- import com.example.dataSource.mapper.BasePersonMapper;
- import org.apache.ibatis.mapping.Environment;
- import org.apache.ibatis.session.Configuration;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
- import javax.sql.DataSource;
- public class MyBatisUtil {
- public static SqlSessionFactory getSqlSessionFactory(DruidDataSource dataSource)
- {
- // 创建 MyBatis 配置
- Configuration configuration = new Configuration();
- configuration.setEnvironment(new Environment("development", new JdbcTransactionFactory(), dataSource));
- // 注册 Mapper
- configuration.addMapper(BasePersonMapper.class);
- // 返回 SqlSessionFactory
- return new SqlSessionFactoryBuilder().build(configuration);
- }
- }
复制代码 3.9 从缓存池中获取目标数据库,查询数据。
在2.5的DataOperateService 类中添加方法,实现以下功能:从缓存池中找到目标数据源,切换数据源,查询该数据源中的base_person表。
- @Autowired
- private DataSourceCacheUtil dataSourceCacheUtil;
- public List<BasePersonModel> getData(String dbName)
- {
- DruidDataSource dataSource=dataSourceCacheUtil.getDataSource(dbName);
- SqlSessionFactory sqlSessionFactory= MyBatisUtil.getSqlSessionFactory(dataSource);
- // 获取 SqlSession
- try(SqlSession sqlSession = sqlSessionFactory.openSession()){
- // 获取 Mapper
- BasePersonMapper basePersonMapper=sqlSession.getMapper(BasePersonMapper.class);
- //查询
- List<BasePersonModel> data=basePersonMapper.getAllData();
- //sqlSession.commit();//如果执行的是insert、update操作,需要提交事务
- return data;
- }
- catch (Exception e) {
- // 记录异常或抛出自定义异常
- e.printStackTrace();
- // 这里可以根据需要返回空列表或重新抛出异常
- return Collections.emptyList();
- }
- }
复制代码 2.10 通过接口将上述功能进行串联
- package com.example.dataSource.controller;
- import com.example.dataSource.dto.BasePersonModel;
- import com.example.dataSource.service.DataOperateService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import java.util.List;
- @RestController
- @RequestMapping("/api/differentDSUse")
- public class DataOperation {
- @Autowired
- DataOperateService dataOperateService;
- @GetMapping("/search")
- public List<BasePersonModel> get()
- {
- return dataOperateService.getData("test");
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |