JDBC基础入门(1)
JDBC(Java Database Connectivity)代表Java编程语言与数据库连接的标准API,然而JDBC只是接口,JDBC驱动才是真正的接口实现,没有驱动无法完成数据库连接. 每个数据库厂商都有自己的驱动,用来连接自己公司的数据库(如Oricle, MySQL, DB2, MS SQLServer).
下面我们以MySQL为例,JDBC编程大致步骤如下:
/**
* @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("%st", users.getObject(i));
}
System.out.println();
}
/* 回收数据库资源(推荐使用Java1.7提供的 可以自动关闭资源的try) */
users.close();
statement.close();
connection.close();
}
}
注意: 需要在pom.xml中添加如下MySQL驱动:
<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
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语句:
Creates a Statement object for sending SQL statements to the database.
其中Connection还提供了如下控制事务/保存点的方法:
Creates a savepoint with the given name in the current transaction and returns the new Savepoint object that represents it.
以上方法还存在不同的重载形式, 详细可参考JDK文档.
ConnectionManger
由于获取Connection的步骤单一,每次可能只是加载的参数不同,因此我们可以将获取Connection的操作封装成一个方法,并使其从配置文件中加载配置:
配置文件形式
## 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中添加如下依赖:
<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,其放在类路径下:
<?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时就默认加载配置文件中的配置, 无须手动配置:
public static DataSource getDataSourceC3P0(String file) {
if (dataSource == null) {
synchronized (ConnectionManger.class) {
if (dataSource == null) {
dataSource = new ComboPooledDataSource();
}
}
}
return dataSource;
}
C3P0配置文件可以配置多个连接信息, 并为每个配置命名, 这样可以方便的通过配置名称来切换配置信息:
public static DataSource getDataSourceC3P0(String file) {
if (dataSource == null) {
synchronized (ConnectionManger.class) {
if (dataSource == null) {
dataSource = new ComboPooledDataSource("mysql-config");
}
}
}
return dataSource;
}
- 《Java程序设计基础》 第8章手记Part 2
- 备忘录模式
- 《Java程序设计基础》 第8章手记Part 1
- 你很有想法,跟我学做菜吧No.3
- 《数据结构》 定长顺序串常用操作代码集合
- 一斤代码深入理解系列(七):微信小程序中使用微信风格样式库-WeUI
- 餐厅老板要累疯了No.2
- linux学习第十九篇:压缩介绍,gzip,bzip2,xz压缩工具
- 区块链?黑人问号?NO.1
- linux学习第二十一篇:安装软件包的三种方法,rpm,yum工具用法,yum搭建本地仓库
- iOS使用自签名证书实现HTTPS请求
- 《Java程序设计基础》 第7章手记
- linux学习第二十三篇:shell介绍,命令历史,命令补全和别名,通配符,输入输出重定向
- Python yield关键字 和 Generator(生成器)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 算法复杂度(二)
- 线性表--顺序表--单向链表(四)
- C语言俄罗斯方块(新版本完整代码)
- 线性表--顺序表--双向链表(六)
- C/C++什么时候使用二级指针,你知道吗?
- 萌新学习C++容易漏掉的知识点,看看你中招了没有(一)
- 萌新不看会后悔的C++string字符串常用知识点总结
- salesforce零基础学习(九十六)项目中的零碎知识点小总结(四)
- CodeForces - 260C
- 疯子的算法总结(九) 图论中的矩阵应用 Part 2 矩阵树 基尔霍夫矩阵定理 生成树计数 Matrix-Tree
- STL常用对象,不会搞得C++跟没学一样
- 桥接模式
- CF--思维练习--CodeForces - 220C Little Elephant and Shifts (STL模拟)
- CF--思维练习--CodeForces - 221C-H - Little Elephant and Problem (思维)
- CF--思维练习--CodeForces - 219C Color Stripe (思维)