Mybatis数据库驱动(mybatisplus支持的数据库)

  本篇文章为你整理了Mybatis数据库驱动(mybatisplus支持的数据库)的详细内容,包含有mybatis 数据库 mybatisplus支持的数据库 mybatis数据库连接 mybatis databaseid Mybatis数据库驱动,希望能帮助你了解 Mybatis数据库驱动。

  Mybatis数据库驱动

  最近在学习mybatis的源码,有一个databaseIdProvider根据不同数据库执行不同sql的功能,我正好有一个mysql还有一个瀚高数据库,就去试了一下,使用如下

  pom文件导入两个数据库的驱动

  

 dependency 

 

   groupId mysql /groupId

   artifactId mysql-connector-java /artifactId

   version 8.0.13 /version

   /dependency

   dependency

   groupId com.highgo /groupId

   artifactId HgdbJdbc /artifactId

   version 6.2.2 /version

   /dependency

  

 

  主启动类.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 User 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 User getUsers(int age);

  

 

  UserMapper.xml

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   !DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

   "http://mybatis.org/dtd/mybatis-3-mapper.dtd"

   mapper namespace="org.mybatis.mapper.UserMapper"

   select id="getUsers" resultType="org.mybatis.pojo.User" databaseId="mysql"

   select * from user where age = #{age}

   /select

   select id="getUsers" resultType="org.mybatis.pojo.User" databaseId="postgresql"

   select * from mybatis.user where age = #{age}

   /select

   /mapper

  

 

  Mybatis配置文件

  

 configuration 

 

   environments default="mysql"

   environment id="mysql"

   transactionManager type="JDBC"/

   dataSource type="POOLED"

   property name="driver" value="com.mysql.cj.jdbc.Driver"/

   property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"/

   property name="username" value="root"/

   property name="password" value="root"/

   /dataSource

   /environment

   environment id="highgo"

   transactionManager type="JDBC"/

   dataSource type="POOLED"

   property name="driver" value="com.mysql.cj.jdbc.Driver"/

   property name="url" value="jdbc:highgo://localhost:5866/highgo?currentSchema=mybatis"/

   property name="username" value="highgo"/

   property name="password" value="Hello@123"/

   /dataSource

   /environment

   /environments

  
 

 

  当我把mybatis配置文件中的环境设置为 environments default="mysql" ,代码执行结果如下

  然后修改环境设置为 environments default="highgo" 后,代码执行结果如下

  不知道您有没有看出问题所在,在上面的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 Driver 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 DriverInfo registeredDrivers = new CopyOnWriteArrayList ();

   //....

   public static java.util.Enumeration Driver getDrivers() {

   java.util.Vector Driver 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("Cant register driver!");

  

 

  所以最终调用的还是DriverManager.registerDriver(new Driver());注册一个驱动,底层就是放入到registeredDrivers这个集合中

  以瀚高的数据库驱动来看,当调用DriverManager.getDrivers时,DriverManager会去加载驱动类,继而驱动类执行static代码块

  最终还是使用DriverManager.registerDriver注册了瀚高的数库驱动

  那么回到UnpooledDataSource类中

  

public class UnpooledDataSource implements DataSource {

 

   private static Map String, Driver registeredDrivers = new ConcurrentHashMap String, Driver

   //.....

   static {

   //这里就会获取到mysql和瀚高的驱动

   Enumeration Driver 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接口,然后在 property name="driver" value="com.drive.MyDrive"/ 使用

  那么Connection connection = DriverManager.getConnection(url, properties);不就是基础的JDBC连接数据库的操作吗

  现在还有一个问题,DriverManager是怎么确定使用哪个数据库驱动呢

  DriverManager.java

  

private static Connection getConnection(

 

   //......

   for(DriverInfo aDriver : registeredDrivers) {

   //检查是否能加载这个驱动到jvm,不能就跳过,底层使用Class.forName 没出异常就是能加载

   if(isDriverAllowed(aDriver.driver, callerCL)) {

   try {

   println(" trying " + aDriver.driver.getClass().getName());

   Connection con = aDriver.driver.connect(url, info);

   if (con != null) {

   // Success!

   println("getConnection returning " + aDriver.driver.getClass().getName());

   return (con);

   } catch (SQLException ex) {

   if (reason == null) {

   reason = ex;

   } else {

   println(" skipping: " + aDriver.getClass().getName());

   //.....

  

 

  底层也很简单,就是遍历驱动集合,每个驱动都去连接一下数据库,如果能连接上说明这个驱动是对的,返回这个驱动创建的连接

  也解答了我自己以前的疑惑和错误的理解

  一直不清楚Class.forName("xxx.Driver")是怎么加载驱动的

  以为mybatis配置文件中的 property name="driver" value="com.mysql.cj.jdbc.Driver"/ 写给哪个环境,哪个环境就使用这个驱动

  现在是明白了

  以上就是Mybatis数据库驱动(mybatisplus支持的数据库)的详细内容,想要了解更多 Mybatis数据库驱动的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: