一、前言
云平台上运行了很多项目,根据项目id动态的切换数据库,mybatis-config.xml启动的时候只会加载一次,很显然无法满足。每次有新项目上线都需要改配置文件然后重启,太low了,所以需要自己根据项目id手动创建SqlSessionFactory进行数据库连接。
原理:将SqlSessionFactory放入Map集合里,判断对应项目id是否创建SqlSessionFactory,若没创建就创建新的,Map有点话就更加动态切换。
动态创建SqlSessionFactory有两种方式:
第一种:是在程序中构建这些对象来创建;
第二种:是依赖springboot来实现;这种方式打jar提交storm集群的时候始终找不到主类,在spring-boot-maven-plugin和maven-shade-plugin之间痛苦了很久果断放弃了,如果是单纯的java或web项目可以用这样方式,毕竟springboot还是很高效的。接下来说的是第一种。
二、在程序中构建SqlSessionFactory
MyBatis框架主要是围绕着SqlSessionFactory这个类进行的,这个的创建过程如下:
- 定义一个Configuration对象,其中包含数据源、事务、mapper文件资源以及影响数据库行为属性设置settings
- 通过配置对象,则可以创建一个SqlSessionFactoryBuilder对象
- 通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例。
- SqlSessionFactory 的实例可以获得操作数据的SqlSession实例,通过这个实例对数据库进行操作
1、重新定义MybatisUtil
package com.siger.storm.utils;
import com.siger.storm.mapper.*;
import com.siger.storm.model.TableName;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import java.util.concurrent.ConcurrentHashMap;
public class MybatisUtil {
public static final Logger log = LogManager.getLogger(MybatisUtil.class);
public static com.siger.storm.constant.Configuration config = com.siger.storm.constant.Configuration.getInstance();
public static ConcurrentHashMap sessionHashMap = new ConcurrentHashMap();
private static SqlSessionFactory sessionFactory;
public static synchronized SqlSession getSqlSession() {
SqlSession session = null;
try {
if (sessionHashMap.get(TableName.getTableName()) != null) {
sessionFactory = (SqlSessionFactory) sessionHashMap.get(TableName.getTableName());
if (sessionFactory.openSession() != null) {
session = sessionFactory.openSession();
}
} else {
sessionFactory = CreateSessionFactory(TableName.getTableName());
if (sessionFactory != null) {
sessionHashMap.put(TableName.getTableName(), sessionFactory);
session = sessionFactory.openSession();
if (sessionFactory.openSession() != null) {
session = sessionFactory.openSession();
}
} else {
log.warn("sessionFactory is null...");
}
}
} catch (Exception e) {
log.error(e.getMessage() + "-->catch Exception");
}
return session;
}
/**
* 根据库名动态创建会话
*
* @param dbName
* @return
*/
public static synchronized SqlSessionFactory CreateSessionFactory(String dbName) {
//创建使用缓存池的数据源
/*
* <dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
*/
// 数据库连接
PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver(config.getString("cloud.mysql.jdbc.driver", ""));
dataSource.setUsername(config.getString("cloud.mysql.user", ""));
dataSource.setPassword(config.getString("cloud.mysql.password", ""));
dataSource.setUrl(config.getString("cloud.mysql.url", "") + dbName +
"?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&autoReconnect=true");
//创建事务
/*
* <transactionManager type="JDBC" />
*/
// 事务
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment(dbName, transactionFactory, dataSource);
//加入资源
/*
* <mapper resource="ssm/BlogMapper.xml"/>
*/
// 创建configuration信息, 添加映射器
// **Mapper.xml 要放在 **Mapper.class 同一级目录下
Configuration configuration = new Configuration(environment);
configuration.addMapper(xxMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
log.info(dbName + " sqlSessionFactory created successfully...");
return sqlSessionFactory;
}
}
2、新建TableName实体类缓存库名
package com.siger.storm.model;
public class TableName {
public static ThreadLocal<String>tablename = new ThreadLocal<>();
public static void setTableName(String cid_pid){
tablename.set(cid_pid);
}
public static String getTableName(){
return tablename.get();
}
public static void removeTableName(){
tablename.remove();
}
}
3、写个测试类测试一下
至于实体类、xxMapper.class和xMapper.xml生成就不多说了,可以用generator自动生成,log和读取配置文件常量类自定义
package com.siger.storm;
import com.siger.storm.dao.impl.ProductionDaoImpl;
import com.siger.storm.model.Production;
import com.siger.storm.model.TableName;
/**
* 描述: 测试
* author: weiy
* create: 2020-09-04 18:12
*/
public class test {
public static ProductionDaoImpl pDaoImpl = new ProductionDaoImpl();
public static void main(String[] args) {
TableName.setTableName("12_79");
final Production production = new Production();
production.setMachineid(23);
production.setStatus(1);
pDaoImpl.insert(production);
}
}
三、注意事项
1、xxMapper.class 和 xxMapper.xml必须在同一级目录下,不然无法识别,底层就是这样定义的,有兴趣朋友可以看下源码。
2、pom.xml需如下配置,不然加载不到src/main/java目录下的xxMapper.xml