缓存池和数据库连接池的使用(Java)
一、基本概念
1. 缓存池(待完善)
2. 数据库连接池(待完善)
二、代码实现
1. 场景描述:
使用ConcurrentHashMap和DruidDataSource 实现以下功能:
①从oracle主数据库的base_dataSource表中查询对应oracle数据库的连接串信息,如果连接池中没有该数据库的连接串信息,将该数据库连接串放入连接池中,下次再次请求该数据库时,先从连接池中获取该数据库信息。
②使用DruidDataSource管理数据库连接,来查询所有数据库的通用表Base_Person表中的数据。
2. 代码实现
2.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>
2.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
2.3 定义实体类
2.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;
}
2.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;
}
2.4 定义Mapper
2.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> {
}
2.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();
}
2.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;
}
}
2.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;
}
}
2.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();
}
}
}
2.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);
}
}
2.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();
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");
}
}
3. 使用到的java包解析:
待完善