首页 > 代码库 > 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为例:
首先要在
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>
其次要在
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"/>
在程序中, 我们就可以这样获取连接了:
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 入门 - 建立连接