不知到大家在开发中有没有遇到过需要动态连接数据库的问题,比如填写个数据库的账号密码和连接地址测试是否可以连接通、动态配置数据库取表格数据等等;我最近就遇到了这样一个问题需要动态配置连接数据库,并且能够在连接数据库时可以动态查询不同表格的数据。面对这个问题一般解决方案可以是直接利用jdbc连接并测试,但是面对容器化,orm框架的不断涌现,这种原生方案无疑是重复性造轮子,并且还未必有现有的框架好用,所以本文将介绍利用spring boot + mybatis-plus
解决该问题。
利用mybatis中SqlSessionFactoryBuilder
这个类的方法动态构建SqlSessionFactory
构建后通过该类不断创建SqlSession
来实现sql语句的动态查询功能,为方便使用本文同时还根据前沿中所遇到的问题构建了一个mapper类。
MySQLConnectUtil
/**
* 数据库动态连接工具类
* @author wsy
*/
public class MySQLConnectUtil {
private static ThreadLocal<MySQLSession> currentSqlSession;
static {
currentSqlSession = new ThreadLocal<>();
}
/**
* 获取session
*
* @param password 密码
* @param url 地址
* @param username 用户名
* @param port 端口
* @return MySQLLog
*/
public static MySQLLogMapper getSession(String url, String username, String password, String databaseName, int port) {
try {
Properties properties = new Properties();
properties.setProperty("jdbc.driver", "com.mysql.cj.jdbc.Driver");
properties.setProperty("jdbc.url", String.format("jdbc:mysql://%s:%s/%s?useSSL=false",
url, port, databaseName));
properties.setProperty("jdbc.username", username);
properties.setProperty("jdbc.password", password);
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, properties);
SqlSession sqlSession = sqlSessionFactory.openSession();
MySQLLogMapper mySQLLogMapper = sqlSession.getMapper(MySQLLogMapper.class);
currentSqlSession.set(MySQLSession.build()
.setSqlSession(sqlSession).setSqlSessionFactory(sqlSessionFactory));
return mySQLLogMapper;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取session
* @param mySQLSession 会话对象
* @return MySQLLog
*/
public static MySQLLogMapper getSession(MySQLSession mySQLSession) {
SqlSession sqlSession = mySQLSession.getSqlSessionFactory().openSession();
mySQLSession.setSqlSession(sqlSession);
return sqlSession.getMapper(MySQLLogMapper.class);
}
public static MySQLSession getMySQLSession() {
return currentSqlSession.get();
}
/**
* 关闭数据库连接
* */
public static void closeSqlSession() {
currentSqlSession.get().getSqlSession().close();
}
/**
* 关闭数据库连接
* @param mySQLSession 会话对象
* */
public static void closeSqlSession(MySQLSession mySQLSession) {
mySQLSession.getSqlSession().close();
}
}
注:这里使用mapper接口时要留意sqlSession的一级缓存,如果不想受一级缓存影响导致脏数据的话,可以每次使用完关掉创建mapper对象的sqlSession类
MySQLLogMapper
/**
* 通用数据查询mapper
* @author wsy
*/
public interface MySQLLogMapper {
/**
* 根据表名统计数据
* @param tableName 表名
* @return int
* */
int count(@Param("tableName") String tableName);
/**
* 查询数据,最大为10w条
* @param tableName 表名
* @param cloum 表字段(一般用于查询游标)
* @param cur 当前游标值
* @return Map
* */
List<Map<String, Object>> selectData(@Param("tableName") String tableName, @Param("cloum") String cloum, @Param("cur") Object cur);
/**
* 获取某个表的主键
* @param tableName 表名
* @return List
List<Map<String, Object>> selectPrimaryKey(@Param("tableName") String tableName);
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.purplestorm.sendemail.mapper.MySQLLogMapper">
<select id="count" resultType="java.lang.Integer">
select count(*) from ${tableName} <where>
<if test="cur != null and cloum != null">
${cloum} > #{cur}
if>
where>;
select>
<select id="selectData" resultType="java.util.LinkedHashMap">
select * from ${tableName}
<where>
<if test="cur != null and cloum != null">
${cloum} > #{cur}
if>
where>
limit <if test="cur != null and cloum == null">
#{cur},
if>10000;
select>
<select id="selectPrimaryKey" resultType="java.util.LinkedHashMap">
SHOW INDEX FROM ${tableName} where Key_name = 'PRIMARY';
select>
mapper>
MySQLSession
/**
* 连接会话类
* @author wsy
*/
public class MySQLSession {
public static MySQLSession build() {
return new MySQLSession();
}
/**
* 会话连接
* */
private SqlSession sqlSession;
public SqlSession getSqlSession() {
return sqlSession;
}
public MySQLSession setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
return this;
}
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
public MySQLSession setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
return this;
}
/**
* 会话连接生产工厂
* */
private SqlSessionFactory sqlSessionFactory;
public void closeSession() {
this.sqlSession.close();
}
}
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="cacheEnabled" value="false"/>
<setting name="localCacheScope" value="STATEMENT"/>
settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mapper/MySQLLogMapper.xml"/>
mappers>
configuration>
注:如果mapper.xml未生效可以尝试clean后再install后启动项目,如果还未生效请检查mybatis-plus.mapper-locations配置是否为classpath:/mapper/*Mapper.xml
对于如上解决方案可能并非最优解,仅供大家参考学习,如有不妥之处或问题欢迎评论区留言或私信。