前言
以前做项目的时候用到了JDBC操作mysql数据库,后面百度面试问到数据库的时候又忘了,最近几天把项目重新看了一遍,查了相关的文章把JDBC做一个总结。
JDBC的结构
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。Java中使用JDBC的整体结构如下图:
JDBC的用途
简单地说,JDBC 主要做四件事:①、加载对应数据库驱动 (Load Driver) ②、与数据库建立连接(connection) ③、发送 操作数据库的语句(createStatement) ④、执行并处理返回结果(executeQuery)如下图:
下面是四个步骤简单的代码:
/*1 加载驱动JDBC_DRIVER="com.mysql.jdbc.Driver"*/
Class.forName(JDBC_DRIVER);
/*2 建立连接DB_URL数据库的url, USER 数据库的用户名, PASS 数据库密码*/
Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER, PASS);
/*3 sql = "select * from student"预编译sql语句*/
PreparedStatement pstmt=conn.prepareStatement(sql);
/*4执行sql语句并返回结果*/
ResultSet rs = pstmt.executeQuery();
安装mysql以及Navicat for mysql
上面以及简单的讲了一下jdbc为了实现在eclipse上运行操作数据库的效果,必须得先安装某种数据库,我安装的是mysql数据库为了方便操作最好安装mysql数据库可视化工具Navicat for mysql。安装好了之后就可以使用Navicat for mysql来管理数据库了。关于如何安装mysql和使Navicat for mysql用可以看下这篇文章MySQL安装安装好了之后我是用Navicat for mysql建立了一个students的数据库以方便后面的测试。数据库如下图
student表很简单就一个id 一个name 一个age 然后自己添加了四条数据。
eclipse配置及运行
首先在eclipse中新建一个DateBase的项目,往项目中添加依赖包mysql-connector-java-5.0.8-bin.jar,然后就来看看如何对上面的数据库进行简单的:插入(insert),更新(update),查询(select)等操作
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
public class JDBCDemo {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; //MySQL数据库驱动
static final String DB_URL = "jdbc:mysql://localhost/students";//数据库地址
static final String USER = "hanking";//用户名
static final String PASS = "hu123";//密码
public static void main(String[] args) {
try {
insert();
update();
select() ;
} catch (Exception e) {
e.printStackTrace();
}
}
// insert() 往数据库中插入一条数据
private static void insert() throws Exception {
Connection conn = null;
PreparedStatement pstsm = null;
try {
// 1:调用工具类获取连接
conn = getConnection();
// 2:准备sql预编译语句
// ?占用一个参数位
String sql = "INSERT INTO student (id,name,age) VALUES (?,?,?);";
// 3:执行sql预编译语句(检查语法)
pstsm =(PreparedStatement) conn.prepareStatement(sql);
// 4:设置传递的参数
pstsm .setInt(1, 5);
pstsm .setString(2, "hanking");
pstsm .setInt(3, 20);
// 5:发送参数,执行sql
// 注意:这里的方法后面没有参数
int result = pstsm .executeUpdate();
System.out.println("影响了" + result + "行");
} catch (Exception e) {
e.printStackTrace();
} finally {
pstsm.close();
conn.close();
// 6:关闭连接
}
}
// 更新数据库中的一条数据
private static int update() {
Connection conn = getConnection();
int i = 0;
String sql = "UPDATE student SET age = ? WHERE id = ?;";
PreparedStatement pstmt;
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
pstmt.setInt(1, 20);
pstmt.setInt(2, 1);
i = pstmt.executeUpdate();
System.out.println("resutl: " + i);
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
return i;
}
//选择出数据库中所有的数据
private static void select() {
Connection conn = getConnection();
String sql = "select * from student";
PreparedStatement pstmt;
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
int col = rs.getMetaData().getColumnCount();
System.out.println("============================");
while (rs.next()) {
for (int i = 1; i <= col; i++) {
System.out.print(rs.getString(i) + "\t");
if ((i == 2) && (rs.getString(i).length() < 8)) {
System.out.print("\t");
}
}
System.out.println("");
}
System.out.println("============================");
} catch (SQLException e) {
e.printStackTrace();
}
}
private static Connection getConnection() {
Connection conn = null;
try {
Class.forName(JDBC_DRIVER); //classLoader,加载对应驱动
conn = (Connection) DriverManager.getConnection(DB_URL, USER, PASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
//最后输出如下
============================
1 hust0 20
2 hust1 24
3 hust2 25
4 hust3 23
5 hanking 20
============================
数据库连接池
上面的例子简单的实现了通过JDBC对数据库进行的简单操作,然而实际项目中往往会使用到数据库连接池,原因:对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
数据库连接池的功能
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。连接复用,通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
数据库连接池的优点
1. 资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2. 更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3. 统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。
数据库连接池的实现
在eclipse中新建一个项目,在项目中加入commons-dbcp-1.4.jar,commons-pool-1.5.6.jar这两个依赖包,还是使用上面的那个数据库进行测试。代码如下
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
public class BasicDataSourceExample {
public static void main(String[] args) {
System.out.println("Setting up data source.");
//创建数据库连接池
DataSource dataSource = setupDataSource("jdbc:mysql://127.0.0.1:3306/students");
System.out.println("Done.");
//
// Now, we can use JDBC DataSource as we normally would.
//
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rset = null;
try {
System.out.println("Creating connection.");
conn = dataSource.getConnection();
System.out.println("Creating statement.");
String sql="SELECT *from student";
stmt = conn.prepareStatement(sql);
System.out.println("Executing statement.");
rset = stmt.executeQuery();
//输出正在使用的数据库连接和空闲的数据库连接
printDataSourceStats(dataSource);
System.out.println("Results:");
int numcols = rset.getMetaData().getColumnCount();
while(rset.next()) {
for(int i=1;i<=numcols;i++) {
System.out.print("\t" + rset.getString(i));
}
System.out.println("");
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try { if (rset != null) rset.close(); } catch(Exception e) { }
try { if (stmt != null) stmt.close(); } catch(Exception e) { }
try { if (conn != null) conn.close(); } catch(Exception e) { }
try {
//关闭数据库连接池
shutdownDataSource(dataSource);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static DataSource setupDataSource(String connectURI) {
BasicDataSource ds = new BasicDataSource();
ds.setUsername("hanking");
ds.setPassword("hu123");
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl(connectURI);
//设置初始化连接数为5
ds.setInitialSize(5);
//设置最大连接数为20
ds.setMaxActive(20);
//设置最大空闲数为 10
ds.setMaxIdle(10);
return ds;
}
public static void printDataSourceStats(DataSource ds) {
BasicDataSource bds = (BasicDataSource) ds;
System.out.println("NumActive: " + bds.getNumActive());
System.out.println("NumIdle: " + bds.getNumIdle());
}
public static void shutdownDataSource(DataSource ds) throws SQLException {
BasicDataSource bds = (BasicDataSource) ds;
bds.close();
System.out.println("bds closed");
}
}
//输出结果
/*Setting up data source.
Done.
Creating connection.
Creating statement.
Executing statement.
NumActive: 1
NumIdle: 4
Results:
1 hust0 20
2 hust1 24
3 hust2 25
4 hust3 23
5 hanking 20
bds closed
*/
由上面代码可知使用数据库连接池很简单,首先建立一个数据库连接池dataSource ,然后从数据库连接池中获得一个空闲的数据库连接conn = dataSource.getConnection() 后面的步骤就和JDBC中的操作是一样的。上面是最简单的例子,还可以对数据库连接池的各种参数进行设置。比如说数据库连接池最大连接数,最小连接数等等。