Mybatis数据库驱动
最近在学习mybatis的源码,有一个databaseIdProvider
根据不同数据库执行不同sql的功能,我正好有一个mysql还有一个瀚高数据库,就去试了一下,使用如下
pom文件导入两个数据库的驱动
mysql
mysql-connector-java
8.0.13
com.highgo
HgdbJdbc
6.2.2
主启动类.java
public class MybatisHelloWorld {
public static void main(String[] args) throws Exception {
String resource = "org/mybatis/config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List users = mapper.getUsers(1);
session.close();
}
}
User.java
public class User {
private Integer id;
private String name;
private Integer age;
//....getter setter 构造..
}
UserMapper.java
public interface UserMapper {
List getUsers(int age);
}
UserMapper.xml
Mybatis配置文件
当我把mybatis配置文件中的环境设置为
,代码执行结果如下
然后我修改环境设置为
后,代码执行结果如下
不知道您有没有看出问题所在,在上面的mybatis配置文件中highgo环境的驱动是com.mysql.cj.jdbc.Driver
但是能连接上瀚高的数据库并且能正常执行sql
当时我也发现这个问题了,于是想研究下原因
首先要找到是哪一段代码进行的操作,那么这里肯定是创建连接的时候,因为驱动不对的话是连接不上的,于是跟着这个思路就去寻找
最后找到方法栈如下
- doGetConnection:200, UnpooledDataSource (org.apache.ibatis.datasource.unpooled)
- doGetConnection:196, UnpooledDataSource (org.apache.ibatis.datasource.unpooled)
- getConnection:93, UnpooledDataSource (org.apache.ibatis.datasource.unpooled)
- popConnection:407, PooledDataSource (org.apache.ibatis.datasource.pooled)
- getConnection:89, PooledDataSource (org.apache.ibatis.datasource.pooled)
- getDatabaseProductName:82, VendorDatabaseIdProvider (org.apache.ibatis.mapping)
- getDatabaseName:66, VendorDatabaseIdProvider (org.apache.ibatis.mapping)
- getDatabaseId:53, VendorDatabaseIdProvider (org.apache.ibatis.mapping)
- databaseIdProviderElement:305, XMLConfigBuilder (org.apache.ibatis.builder.xml)
- parseConfiguration:123, XMLConfigBuilder (org.apache.ibatis.builder.xml)
- parse:97, XMLConfigBuilder (org.apache.ibatis.builder.xml)
- build:82, SqlSessionFactoryBuilder (org.apache.ibatis.session)
- build:67, SqlSessionFactoryBuilder (org.apache.ibatis.session)
- main:32, MybatisHelloWorld (org.mybatis)
UnpooledDataSource.java
private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver();
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}
private synchronized void initializeDriver() throws SQLException {
//判断这个驱动是否注册过
if (!registeredDrivers.containsKey(driver)) {
Class> driverType;
try {
if (driverClassLoader != null) {
driverType = Class.forName(driver, true, driverClassLoader);
} else {
driverType = Resources.classForName(driver);
}
Driver driverInstance = (Driver)driverType.newInstance();
DriverManager.registerDriver(new DriverProxy(driverInstance));
registeredDrivers.put(driver, driverInstance);
} catch (Exception e) {
throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
}
}
}
先判断需要加载的驱动是否已经注册了
那这里面的两个驱动是从哪里来的呢?
就在这个UnpooledDataSource类中的静态块里面
static {
Enumeration drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
registeredDrivers.put(driver.getClass().getName(), driver);
}
}
而DriverManager中有一个集合用来存储所有已经注册的数据库连接驱动
public class DriverManager {
// List of registered JDBC drivers
private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList();
//....
public static java.util.Enumeration getDrivers() {
java.util.Vector result = new java.util.Vector();
Class> callerClass = Reflection.getCallerClass();
// Walk through the loaded registeredDrivers.
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerClass)) {
result.addElement(aDriver.driver);
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
return (result.elements());
}
//......
}
那么问题又来了,DriverManager里面的瀚高数据库驱动啥时候放进去的呢
在学java基础的jdbc时,肯定都写过类似这样的代码
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con= DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx","root","XXXXXX");
Statement stat=con.createStatement();
//......
}
当时这段Class.forName("com.mysql.cj.jdbc.Driver");
就告诉你是加载驱动,有的博客写了这段代码,有的没写,具体操作一直都不清楚
首先JDK5版本以后可以不用显式调用这段话,DriverManager会自己去合适的驱动,前提是这个驱动存在于CLASSPATH下
其次,它是怎么加载的呢?为啥Class.forName就能加载呢?
当一个类被加载到JVM时会执行静态代码块,我们以mysql的驱动举例子
package com.mysql.cj.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
所以最终调用的还是DriverManager.registerDriver(new Driver());
注册一个驱动,底层就是放入到registeredDrivers这个集合中
以瀚高的数据库驱动来看,当调用DriverManager.getDrivers
时
最终还是使用DriverManager.registerDriver
注册了瀚高的数库驱动
那么回到UnpooledDataSource类中
public class UnpooledDataSource implements DataSource {
private static Map registeredDrivers = new ConcurrentHashMap();
//.....
static {
//这里就会获取到mysql和瀚高的驱动
Enumeration drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
registeredDrivers.put(driver.getClass().getName(), driver);
}
}
//.....
private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver();
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}
}
initializeDriver()
加载一些其他的驱动,例如我们自定义一个类,实现Driver接口,然后在
使用
那么Connection connection = DriverManager.getConnection(url, properties);
不就是基础的JDBC连接数据库的操作吗
也解答了我自己以前的疑惑或者错误的理解
- 一直不清楚Class.forName(“”)的作用
- 以为mybatis配置文件中的
写给那个环境,那个环境就使用这个驱动
现在是明白了
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net