JDBC介绍

96 阅读2分钟

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。我们通常说的JDBC是面向关系型数据库的。

下面是使用JDBC连接MySQL数据库的简单例子:

image.png

然后看下jdbc的最重要的几个接口和类 image.png

  • DriverManager:用于管理一组JDBC驱动程序的基本服务
  • DataSource:用于连接到此DataSource对象所表示的物理数据源的工厂。作为DriverManager功能的替代方案,DataSource对象是获取连接的首选方式
  • Driver:每个驱动程序类必须实现的接口。DriverManager将尝试加载尽可能多的驱动程序,然后对于任何给定的连接请求,它将依次要求每个驱动程序尝试连接到目标URL
  • Connection:与特定数据库的连接(会话)。在连接的上下文中执行SQL语句并返回结果
  • Statement:用于执行静态SQL语句并返回其生成的结果的对象
  • PreparedStatement:表示预编译SQL语句的对象。SQL语句是预编译的,并存储在PreparedStatement对象中。然后可以使用此对象多次有效地执行此语句

Driver接口的一些驱动程序实现:

image.png

看一下现在用的比较多的druid是怎么注册驱动程序的

public class DruidDriver implements Driver, DruidDriverMBean {

    private static final DruidDriver instance = new DruidDriver();

    // 静态代码块,用于初始化变量
    static {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                registerDriver(instance);
                return null;
            }
        });
    }
    
        public static boolean registerDriver(Driver driver) {
          try {
            // 注意这里,使用jdbc提供的驱动管理器去加载具体的实现
            DriverManager.registerDriver(driver);

            try {
                MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

                ObjectName objectName = new ObjectName(MBEAN_NAME);
                if (!mbeanServer.isRegistered(objectName)) {
                    mbeanServer.registerMBean(instance, objectName);
                }
            } catch (Throwable ex) {
                if (LOG == null) {
                    LOG = LogFactory.getLog(DruidDriver.class);
                }
                LOG.warn("register druid-driver mbean error", ex);
            }

            return true;
        } catch (Exception e) {
            if (LOG == null) {
                LOG = LogFactory.getLog(DruidDriver.class);
            }

            LOG.error("registerDriver error", e);
        }

        return false;
    }
    
    // 连接数据库  
    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        if (!acceptsURL(url)) {
            return null;
        }

        connectCount.incrementAndGet();

        DataSourceProxyImpl dataSource = getDataSource(url, info);

        return dataSource.connect(info);
    }
    

private static final ConcurrentMap<String, DataSourceProxyImpl> proxyDataSources = new ConcurrentHashMap<String, DataSourceProxyImpl>(16, 0.75f, 1);

// 这里建立的都是单个连接,不是连接池的实现方式。连接池的实现可以看DruidDataSource
private DataSourceProxyImpl getDataSource(String url, Properties info) throws SQLException {
        DataSourceProxyImpl dataSource = proxyDataSources.get(url);

        if (dataSource == null) {
            DataSourceProxyConfig config = parseConfig(url, info);

            Driver rawDriver = createDriver(config.getRawDriverClassName());

            DataSourceProxyImpl newDataSource = new DataSourceProxyImpl(rawDriver, config);

            {
                String property = System.getProperty("druid.filters");
                if (property != null && property.length() > 0) {
                    for (String filterItem : property.split(",")) {
                        FilterManager.loadFilter(config.getFilters(), filterItem);
                    }
                }
            }
            {
                int dataSourceId = createDataSourceId();
                newDataSource.setId(dataSourceId);

                for (Filter filter : config.getFilters()) {
                    filter.init(newDataSource);
                }
            }

            DataSourceProxy oldDataSource = proxyDataSources.putIfAbsent(url, newDataSource);
            if (oldDataSource == null) {
                if (config.isJmxOption()) {
                    JMXUtils.register("com.alibaba.druid:type=JdbcStat", JdbcStatManager.getInstance());
                }
            }

            dataSource = proxyDataSources.get(url);
        }
        return dataSource;
    }

}

最后再看下mybatis怎么获取数据库连接的

public interface Transaction {
    // 获取数据库连接
    Connection getConnection() throws SQLException;
}

/**  
* Transaction有三个实现类,分别是SpringManagedTransaction、JdbcTransaction、ManagedTransaction  
* ManagedTransaction是一种由容器或框架来管理的事务,而不是 MyBatis 内部来管理
* Transaction 接口的默认实现是 JdbcTransaction
* 现在项目大部分都是使用spring和myBatis框架进行开发
*/
public class SpringManagedTransaction implements Transaction {
    @Override  
    public Connection getConnection() throws SQLException {  
        if (this.connection == null) {  
            openConnection();  
        }  
        return this.connection;  
    }
    
    private void openConnection() throws SQLException {
        // 通过spring的DataSourceUtils去获取spring dataSource
        this.connection = DataSourceUtils.getConnection(this.dataSource);  
        this.autoCommit = this.connection.getAutoCommit();  
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);  

        LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"  
        + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");  
    }
}