首页 > 代码库 > JDBC 入门 - 建立连接

JDBC 入门 - 建立连接

JDBC 入门 - 建立连接

建立连接

在于数据库交互的时候, 第一件事是和数据源(Data Source)也就是数据库建立连接(Connection). 可以从这两个类从数据源取得连接:

  • DriverManager: 在 java.sql 包中, 连接时必须要指定 URL 去连接, 在 JDBC4.0 之前都要显式地去加载驱动类, JDBC4.0后自动加载 CLASSPATH 中的驱动.

  • DataSource: 在 javax.sql 包中, 与 Driver Manager 不同的是, 一个数据库驱动是一个DataSource. DataSource 可以提供连接池功能, 在 EE 中使用较为频繁.

下面以 JAVADB 和 MySQL 为例, 在 JAVA DB 中有以下表:

    CREATE TABLE tags    (    id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),    name VARCHAR(32) NOT NULL,    CONSTRAINT primary_key PRIMARY KEY (id)    );

 

表结构如下:

    ij> describe tags;    COLUMN_NAME         |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL&    ------------------------------------------------------------------------------    ID                  |INTEGER  |0   |10  |10    |AUTOINCRE&|NULL      |NO          NAME                |VARCHAR  |NULL|NULL|32    |NULL      |64        |NO

 

(Note: JAVA DB 有两种运行模式, 一种是 Embedded 模式, 一种是 Client-Server 模式. 前者的url是jdbc:derby:dbName, Embedded模式只能由运行时的Java程序访问; 后者url是jdbc:derby://host:port/dbName, 可以由Java程序和ij工具同时访问. 在这里,我们适用后者).

在 MySQL 中有以下表:

    CREATE TABLE posts    (    id INTEGER NOT NULL AUTO_INCREMENT,    title VARCHAR(255) NOT NULL,    content TEXT NOT NULL,    dt_create DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,    visible BOOLEAN NOT NULL DEFAULT TRUE,    PRIMARY KEY (id)    );

 

表结构如下:

    mysql> describe posts;    +-----------+--------------+------+-----+-------------------+----------------+    | Field     | Type         | Null | Key | Default           | Extra          |    +-----------+--------------+------+-----+-------------------+----------------+    | id        | int(11)      | NO   | PRI | NULL              | auto_increment |    | title     | varchar(255) | NO   |     | NULL              |                |    | content   | text         | NO   |     | NULL              |                |    | dt_create | datetime     | NO   |     | CURRENT_TIMESTAMP |                |    | visible   | tinyint(1)   | NO   |     | 1                 |                |    +-----------+--------------+------+-----+-------------------+----------------+    5 rows in set (0.01 sec)

 

使用Driver Manager

在数据库中建立好表后, 我们该往数据库中写数据了, 以下代码示例了如何从 DriverManager 新建一个连接, 并往数据库中插入一条数据:

public class BlogDB {        private static Connection getConnection(Properties props) throws SQLException {            String url = props.getProperty("url");            String user = props.getProperty("user");            Connection conn = null;            if (user.length() == 0) {                conn = DriverManager.getConnection(url);            } else {                conn = DriverManager.getConnection(url, props);            }            String dbName = props.getProperty("dbName");            conn.setCatalog(dbName);            return conn;        }        public static void InsertNewPost() throws SQLException, IOException {            Properties dbProps = new Properties();            dbProps.load(ClassLoader.getSystemResourceAsStream("db.mysql.props"));            Connection conn = getConnection(dbProps);            Statement stmt = conn.createStatement();            String sql = "INSERT INTO posts "                       + "VALUES (NULL, \"First Post\", \"Hello!\", DEFAULT, true)";            int nRows = stmt.executeUpdate(sql);            assert(nRows == 1);            stmt.close();            conn.close();        }        public static void InsertNewTag() throws SQLException, IOException {            Properties dbProps = new Properties();            dbProps.load(ClassLoader.getSystemResourceAsStream("db.javadb.props"));            Connection conn = getConnection(dbProps);            Statement stmt = conn.createStatement();            String sql = "INSERT INTO TAGS "                    + "VALUES (DEFAULT, \‘Java\‘)";            int nRows = stmt.executeUpdate(sql);            assert(nRows == 1);            stmt.close();            conn.close();        }        public static void main(String[] args) throws IOException, SQLException {            BlogDB.InsertNewPost();            BlogDB.InsertNewTag();        }    }

 

在这个例子中, 有以下两个要点:

  • DriverManager 同时管理着 Mysql 和 Derby 这两个数据库驱动
  • 当需要一个数据库连接的时候, 通过调用DriverManager.getConnection(url), 根据url的不同来获取相应的数据库连接.

使用 DataSource

使用 DataSource 建立连接时, 可以不用传入 url. 值得注意的是, 虽然 DataSource 接口相同, 但是各个厂商的完成度有差异. 而且没有 DataSourceManager 这样的接口, 对于 DataSource 需要我们自己管理. 下面我们修改 DriverManager 的代码, 从 DataSource 新建连接:

public class BlogDB {        private static final String KEY_MYSQL = "MYSQL";        private static final String KEY_DERBY = "DERBY";        private static Map<String, DataSource> dsMap = new HashMap<String, DataSource>();        private static Connection getConnection(Properties props) throws SQLException {            String url = props.getProperty("url");            String dbName = props.getProperty("dbName");            String user = props.getProperty("user");            String pswd = props.getProperty("password");            Connection conn = null;            if (url.matches("^jdbc:mysql:.*")) {                conn = getMySQLConnection(dbName, user, pswd);            } else if (url.matches("^jdbc:derby:.*")){                conn = getDerbyConnection(dbName, user, pswd);            }            return conn;        }        private static Connection getMySQLConnection(String dbName, String user, String pswd) throws SQLException {            Connection conn = null;            MysqlDataSource ds = null;            if (!dsMap.containsKey(KEY_MYSQL)) {                ds = new MysqlDataSource();                ds.setDatabaseName(dbName);            } else {                ds = (MysqlDataSource)dsMap.get(KEY_MYSQL);            }            conn = ds.getConnection(user, pswd);            if (!dsMap.containsKey(KEY_MYSQL)) {                dsMap.put(KEY_MYSQL, ds);            }            return conn;        }        private static Connection getDerbyConnection(String dbName, String user, String pswd) throws SQLException {            Connection conn = null;            ClientDataSource ds = null;            if (!dsMap.containsKey(KEY_DERBY)) {                ds = new ClientDataSource();                ds.setDatabaseName(dbName);            } else {                ds = (ClientDataSource)dsMap.get(KEY_DERBY);            }            if (user != null && user.length() > 0) {                conn = ds.getConnection(user, pswd);            } else {                conn = ds.getConnection();            }            if (!dsMap.containsKey(KEY_DERBY)) {                dsMap.put(KEY_DERBY, ds);            }            return conn;        }        public static void InsertNewPost() throws SQLException, IOException {}        public static void InsertNewTag() throws SQLException, IOException {}        public static void main(String[] args) throws IOException, SQLException {}    }

 

可以看出:

  • 调用 DataSource.getConnection() 的时候, 我们不用传入 URL.
  • 需要自己管理 DataSource, 我们在 getConnection(Properties props) 中解析url只是为了解析DataSource的类型, 为不同的类型返回不同连接. 这样可以适用和 DriverManager 例子 相同的配置文件.

在 EE 中使用 DataSource

在 EE 中, DataSource 不需要手动去 new 出来, 一般是修改配置添加数据源, 然后通过 JNDI 在程序中获取对 DataSource的引用:

以 Tomcat 和 Mysql为例:

  1. 首先要在 WEB-INF/web.xml 中 添加一个资源, 类型为javax.sql.DataSource, 并修改 JNDI 名字为 jdbc/testDB:

     <resource-ref>     <description>         Resource reference to a factory for java.sql.Connection         instances that may be used for talking to a particular         database that is configured in the         configurartion for the web application.     </description>     <res-ref-name>         jdbc/testDB     </res-ref-name>     <res-type>         javax.sql.DataSource     </res-type>     <res-auth>         Container     </res-auth> </resource-ref>

     

  2. 其次要在 META-INF/context.xml 中添加 DataSource 相关配置:

     <Resource name="jdbc/testDB"           auth="Container"           type="javax.sql.DataSource"           username="root"           password="5858982Znx"           driverClassName="com.mysql.jdbc.Driver"           url="jdbc:mysql://localhost:3306/testDB"           maxActive="100"           maxIdle="30"           maxWait="10000"           removeAbandoned="true"           removeAbandonedTimeout="60"           logAbandoned="true"/>

     

  3. 在程序中, 我们就可以这样获取连接了:

     public Connection getConnection() throws NamingException, SQLException {     Context initCtx = new InitialContext();     Context envCtx = (Context) initCtx.lookup("java:comp/env");     DataSource ds = (DataSource)             envCtx.lookup("jdbc/testDB");     Connection conn = ds.getConnection();     conn.setAutoCommit(false);     return conn; }

     

JDBC 入门 - 建立连接