场景
公司需要从数量不定,类型可能不同的第三方数据库读取数据。
需求
数据库信息需要动态配置(如从数据库读取),需要动态设置DataSource,且考虑到线程安全。
所以写死的多数据源满足不了。
下面代码已满足基本要求,便捷性自行扩展。
解释:ComRecord 它是个自定义的map。
数据源代码:
package com.tyl.localhis.dao;
import com.tyl.comm.basic.ComRecord;
import com.tyl.comm.util.StringUtils;
import com.tyl.localhis.dao.dto.ProcedureDto;
import com.tyl.localhis.entity.config.SyncConfigDb;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description 通用访问数据库类,该类可实现动态多数据源,且线程安全
* @author tangyaliang
* @time 2021/12/11 22:56
*/
@Service
public class ComDao {
private final ThreadLocal<MyJdbcTemplate> local = new ThreadLocal<>();
private final Map<String, HikariDataSource> map = new HashMap<>();
private final MyJdbcTemplate template = new MyJdbcTemplate();
/**
* 没有默认数据源
*/
public ComDao(){}
/**
* 支持配置默认数据源,一般用不上
* @param dataSource 默认数据源
*/
public ComDao(DataSource dataSource){
template.setDataSource(dataSource);
local.set(template);
}
/**
* @param config 数据库链接配置,db_id,db_url,db_name,db_pwd
* @description 根据不同数据库用户名切换DataSource
* @author tangyaliang 线程安全
* @time 2021/12/11 22:56
*/
public void setDataSource(SyncConfigDb config) {
HikariDataSource dataSource = map.get(config.getDbId());
if (dataSource == null) {
dataSource = new HikariDataSource();
//数据库url
dataSource.setJdbcUrl(config.getDbUrl());
//数据库用户名
dataSource.setUsername(config.getDbName());
//数据库密码
dataSource.setPassword(config.getDbPwd());
if (!StringUtils.isEmpry(config.getDbDriverName())) {
dataSource.setDriverClassName(config.getDbDriverName());
}
//DataSource放入map中,等待使用
map.put(config.getDbId(), dataSource);
}
template.setDataSource(dataSource);
local.set(template);
}
/**
* 执行sql语句
* @param sql sql
* @return 结果集
*/
public List<ComRecord> query(String sql) {
return local.get().query(sql, new ComRowMapper(local.get().getDbEnCoding()));
}
/**
* 调用存储过程返回结果集
* 目前可以调用oracle游标结果集,mysql结果集,其他微测试
* @return 结果集
*/
public List<ComRecord> queryProcedureByRefcursor(ProcedureDto dto) {
//参数名称不区分大小写
local.get().setResultsMapCaseInsensitive(true);
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(local.get());
//设置储存过程名称
simpleJdbcCall.withProcedureName(dto.getProcedurName());
//设置存储过程游标或数据集名称,如果参数名称与存储过程中out名称相对应则返回ComRowMapper类型,名称对应不上返回linkdlist
simpleJdbcCall.returningResultSet(dto.getRefcursorName(), new ComRowMapper(local.get().getDbEnCoding()));
//.returningResultSet("data", BeanPropertyRowMapper.newInstance(Clazz.class));Clazz.class可以直接转化为实体类型
//设置输入参数
Map<String, Object> map;
if (dto.getInParames() == null || dto.getInParames().size() == 0) {
map = simpleJdbcCall.execute(new HashMap<>(0));
} else {
map = simpleJdbcCall.execute(dto.getInParames());
}
return (List<ComRecord>) map.get(dto.getRefcursorName());
}
/**
* @description 通用RowMapper,其他地方用不到,所以定义为成员内部类
* @author tangyaliang
* @time 2021/12/11
*/
class ComRowMapper implements RowMapper {
String charSet;
public ComRowMapper(){
}
public ComRowMapper(String charSet){
this.charSet = charSet;
}
@Override
public ComRecord mapRow(ResultSet rs, int rowNum) throws SQLException {
ComRecord record = new ComRecord();
ResultSetMetaData red = rs.getMetaData();
DefaultLobHandler handler = new DefaultLobHandler();
String columnName, value;
try {
for (int i = 1; i <= red.getColumnCount(); i++) {
columnName = red.getColumnName(i);
if (red.getColumnTypeName(i).equalsIgnoreCase("CLOB")) {
value = handler.getClobAsString(rs, i);
} else {
value = rs.getString(i);
}
//如果数据库字符集不是GBK,修改为GBK
if (!"GBK".equalsIgnoreCase(charSet) && charSet != null) {
if (value == null) continue;
value = new String(value.getBytes(charSet), "GBK");
}
record.put(columnName, value);
}
} catch (Exception e) {
e.printStackTrace();
}
return record;
}
}
}
测试代码:用的定时任务,一秒钟执行一次
private final ComDao comDao;
@Scheduled(cron = "0/1 * * * * ?")
public void data1() {
SyncConfigDb db = new SyncConfigDb();
db.setDbId("COMM");
db.setDbUrl("jdbc:oracle:thin:@192.168.1.115:1521:orcl");
db.setDbName("COMM");
db.setDbPwd("123");
comDao.setDataSource(db);
List<ComRecord> list = comDao.query("select * from tablename1");
System.out.println("data1==" + list.size());
}
@Scheduled(cron = "0/1 * * * * ?")
public void data2() {
SyncConfigDb db = new SyncConfigDb();
db.setDbId("TYL");
db.setDbUrl("jdbc:oracle:thin:@192.168.1.115:1521:orcl");
db.setDbName("TYL");
db.setDbPwd("123");
comDao.setDataSource(db);
List<ComRecord> list = comDao.query("select * from tablename2");
System.out.println("data2==" + list.size());
}
牛逼,真他么想给自己点个赞。