前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDBC基础入门(1)

JDBC基础入门(1)

作者头像
Java帮帮
发布2018-03-16 17:35:50
7360
发布2018-03-16 17:35:50
举报

JDBC(Java Database Connectivity)代表Java编程语言与数据库连接的标准API,然而JDBC只是接口,JDBC驱动才是真正的接口实现,没有驱动无法完成数据库连接. 每个数据库厂商都有自己的驱动,用来连接自己公司的数据库(如Oricle, MySQL, DB2, MS SQLServer).

下面我们以MySQL为例,JDBC编程大致步骤如下:

代码语言:javascript
复制
/**
 * @author jifang
 * @since 16/2/18 上午9:02.
 */
public class SQLClient {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        /* 加载数据库驱动 */
        Class.forName("com.mysql.jdbc.Driver");
        /* 通过 DriverManager 获取数据库连接 */
        Connection connection = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");
        /* 通过 Connection 创建 Statement */
        Statement statement = connection.createStatement();
        /* 通过 Statement 执行SQL */
        ResultSet users = statement.executeQuery("SELECT * FROM user");
        /* 操作 ResultSet 结果集 */
        int columnCount = users.getMetaData().getColumnCount();
        while (users.next()) {
            for (int i = 1; i <= columnCount; ++i) {
                System.out.printf("%s\t", users.getObject(i));
            }
            System.out.println();
        }
        /* 回收数据库资源(推荐使用Java1.7提供的 可以自动关闭资源的try) */
        users.close();
        statement.close();
        connection.close();
    }
}

注意: 需要在pom.xml中添加如下MySQL驱动:

代码语言:javascript
复制
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.36</version>
</dependency>

注: ResultSet参数columnIndex索引从1开始,而不是0!

ConnectionManger

DriverManger

JDBC规定: 驱动类在被加载时,需要主动把自己注册到DriverManger中:

com.mysql.jdbc.Driver

代码语言:javascript
复制
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

代码显示:只要去加载com.mysql.jdbc.Driver类那么就会执行static块, 从而把com.mysql.jdbc.Driver注册到DriverManager中.

java.sql.DriverManager是用于管理JDBC驱动的服务类,其主要功能是获取Connection对象:

1. static Connection getConnection(String url, Properties info)

2. static Connection getConnection(String url, String user, String password)

另: 还可以在获取Connection的URL中设置参数,如: jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=UTF8

useUnicode=true&characterEncoding=UTF8指定连接数据库的过程中使用Unicode字符集/UTF-8编码;

Connection

java.sql.Connection代表数据库连接,每个Connection代表一个物理连接会话, 该接口提供如下创建Statement的方法, 只有获取Statement之后才可执行SQL语句:

代码语言:javascript
复制
Creates a Statement object for sending SQL statements to the database.

其中Connection还提供了如下控制事务/保存点的方法:

代码语言:javascript
复制
Creates a savepoint with the given name in the current transaction and returns the new Savepoint object that represents it.

以上方法还存在不同的重载形式, 详细可参考JDK文档.

ConnectionManger

由于获取Connection的步骤单一,每次可能只是加载的参数不同,因此我们可以将获取Connection的操作封装成一个方法,并使其从配置文件中加载配置:

配置文件形式

代码语言:javascript
复制
## Data Source
mysql.driver.class=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://host:port/database
mysql.user=admin
mysql.password=admin
ConnectionManger
/**
 * @author jifang
 * @since 16/2/19 上午10:40.
 */
public class ConnectionManger {
    /*获取原生Connection*/
    public static Connection getConnection(String file) {
        Properties config = SQLUtil.loadConfig(file);
        try {
            Class.forName(config.getProperty("mysql.driver.class"));
            String url = config.getProperty("mysql.url");
            String username = config.getProperty("mysql.user");
            String password = config.getProperty("mysql.password");
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}
SQLUtil
/**
 * @author jifang
 * @since 16/2/18 上午8:24.
 */
public class SQLUtil {
    /**
     * 加载.properties配置文件
     *
     * @param file
     * @return
     */
    public static Properties loadConfig(String file) {
        Properties properties = new Properties();
        try {
            properties.load(ClassLoader.getSystemResourceAsStream(file));
            return properties;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

数据库连接池

前面通过DriverManger获得Connection, 一个Connection对应一个实际的物理连接,每次操作都需要打开物理连接, 使用完后立即关闭;这样频繁的打开/关闭连接会造成不必要的数据库系统性能消耗.

数据库连接池提供的解决方案是:当应用启动时,主动建立足够的数据库连接,并将这些连接组织成连接池,每次请求连接时,无须重新打开连接,而是从池中取出已有连接,使用完后并不实际关闭连接,而是归还给池.

JDBC数据库连接池使用javax.sql.DataSource表示, DataSource只是一个接口, 其实现通常由服务器提供商(如WebLogic, WebShere)或开源组织(如DBCP,C3P0和HikariCP)提供.

数据库连接池的常用参数如下:

数据库初始连接数;

连接池最大连接数;

连接池最小连接数;

连接池每次增加的容量;

C3P0

Tomcat默认使用的是DBCP连接池,但相比之下,C3P0则比DBCP更胜一筹(hibernate推荐使用C3P0),C3P0不仅可以自动清理不再使用的Connection, 还可以自动清理Statement/ResultSet, 使用C3P0需要在pom.xml中添加如下依赖:

代码语言:javascript
复制
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>mchange-commons-java</artifactId>
    <version>0.2.11</version>
</dependency>
ConnectionManger
public class ConnectionManger {
    /*双重检测锁保证DataSource单例*/
    private static DataSource dataSource;
    /*获取DataSource*/
    public static DataSource getDataSourceC3P0(String file) {
        if (dataSource == null) {
            synchronized (ConnectionManger.class) {
                if (dataSource == null) {
                    Properties config = SQLUtil.loadConfig(file);
                    try {
                        ComboPooledDataSource source = new ComboPooledDataSource();
                        source.setDriverClass(config.getProperty("mysql.driver.class"));
                        source.setJdbcUrl(config.getProperty("mysql.url"));
                        source.setUser(config.getProperty("mysql.user"));
                        source.setPassword(config.getProperty("mysql.password"));
                        // 设置连接池最大连接数
                        source.setMaxPoolSize(Integer.valueOf(config.getProperty("pool.max.size")));
                        // 设置连接池最小连接数
                        source.setMinPoolSize(Integer.valueOf(config.getProperty("pool.min.size")));
                        // 设置连接池初始连接数
                        source.setInitialPoolSize(Integer.valueOf(config.getProperty("pool.init.size")));
                        // 设置连接每次增量
                        source.setAcquireIncrement(Integer.valueOf(config.getProperty("pool.acquire.increment")));
                        // 设置连接池的缓存Statement的最大数
                        source.setMaxStatements(Integer.valueOf(config.getProperty("pool.max.statements")));
                        // 设置最大空闲时间
                        source.setMaxIdleTime(Integer.valueOf(config.getProperty("pool.max.idle_time")));
                        dataSource = source;
                    } catch (PropertyVetoException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return dataSource;
    }
    /*获取Connection*/
    public static Connection getConnectionC3P0(String file) {
        return getConnection(getDataSourceC3P0(file));
    }
    public static Connection getConnection(DataSource dataSource) {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    // ...
}

C3P0还可以使用配置文件来初始化连接池(配置文件可以是properties/XML, 在此仅介绍XML),C3P0配置文件名必须为c3p0-config.xml,其放在类路径下:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="jdbcUrl">jdbc:mysql://host:port/database</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">user</property>
        <property name="password">password</property>
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">3</property>
        <property name="maxPoolSize">20</property>
    </default-config>
    <named-config name="mysql-config">
        <property name="jdbcUrl">jdbc:mysql://host:port/common</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">user</property>
        <property name="password">password</property>
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">3</property>
        <property name="maxPoolSize">20</property>
    </named-config>
</c3p0-config>

这样, 我们在创建ComboPooledDataSource时就默认加载配置文件中的配置, 无须手动配置:

代码语言:javascript
复制
public static DataSource getDataSourceC3P0(String file) {
    if (dataSource == null) {
        synchronized (ConnectionManger.class) {
            if (dataSource == null) {
                dataSource = new ComboPooledDataSource();
            }
        }
    }
    return dataSource;
}

C3P0配置文件可以配置多个连接信息, 并为每个配置命名, 这样可以方便的通过配置名称来切换配置信息:

代码语言:javascript
复制
public static DataSource getDataSourceC3P0(String file) {
    if (dataSource == null) {
        synchronized (ConnectionManger.class) {
            if (dataSource == null) {
                dataSource = new ComboPooledDataSource("mysql-config");
            }
        }
    }
    return dataSource;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java帮帮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档