JDBC详解
一 JDBC基本操作
MySQL的JDBC驱动包: mysql-connector-java-5.1.38-bin.jar
- mysql-connector-java-5.1.38-bin.jar
是MySQL的JDBC驱动包,用JDBC连接MySQL数据库时必须使用该jar包。
- maven
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
- 1 加载驱动
- 2 获得连接
- 3 基本操作,执行SQL语句
- 4 遍历结果集
- 5 释放资源
代码如下
//1 加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2 获得连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/han","root","123");
//3 基本操作,执行SQL
//3.1 获得执行SQL语句的对象
Statement createStatement = conn.createStatement();
//3.2 编写SQL语句
String sql = "select * from orderitem";
//3.3 执行SQL
ResultSet resultSet = createStatement.executeQuery(sql);
//3.4 遍历结果集
while(resultSet.next()){
System.out.println(resultSet.getInt("id"));
System.out.println(resultSet.getString("product"));
System.out.println(resultSet.getDouble("price"));
}
//4. 释放资源
resultSet.close();
createStatement.close();
conn.close();
}
对象详解:
DriverManager:驱动管理类
- 作用 1 : 注册驱动. 实际开发中一般不会使用,它会导致驱动注册两次
- 作用 2 : 获得连接
- getConnection: 用来获得与数据库连接的方法:这个方法中有三个参数:
url :与数据库连接的路径 user :与数据库连接的用户名 password :与数据库连接的密码
- 主要关注的是url的写法:
jdbc:mysql://localhost:3306/web_test3 jdbc :连接数据库的协议 mysql :是jdbc的子协议 localhost :连接的MySQL数据库服务器的主机地址。(连接是本机就可以写成localhost),如果连接不是本机的,就需要写上连接主机的IP地址。 3306 :MySQL数据库服务器的端口号 web_test3 :数据库名称 url如果连接的是本机的路径,可以简化为如下格式: jdbc:mysql:///web_test3
connection : 数据库连接对象
- 作用 1 创建执行SQL语句的对象
- 作用 2 管理事务
statement ; 执行SQL
- 执行SQL
- 批处理
- ResultSet :结果集
- 通过SQL语句查询的结果
JDBC的增删改查就不多说了,都是最基本的东西
我们来看一下工具类的抽取和配置文件的设置
-
-
工具类
public class JDBCUtils {
private static final String driverClassName;
private static final String url;
private static final String username;
private static final String password;
// 静态代码块,随着类的加载二加载
static {
// 获取属性文件中的内容
Properties pro = new Properties();
try {
pro.load(new FileInputStream("src/db.properties"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
driverClassName = pro.getProperty("driverClassName");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
}
/**
* 注册驱动
* @throws ClassNotFoundException
*/
public static void loadDriver() throws ClassNotFoundException{
Class.forName(driverClassName);
}
/**
* 获得连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url,username,password);
}
/**
* 释放资源的方法
*/
public static void release(Statement stmt,Connection conn){
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
/**
* 释放资源
* @param rs
* @param stmt
* @param conn
*/
public static void release(ResultSet rs,Statement stmt,Connection conn){
// 资源释放:
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
配置文件 db.properties :
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/han
username=root
password=123
二 c3p0连接池
连接池是装有连接的容器,使用连接的话,可以从连接池中进行获取,使用完成之后将连接归还给连接池。
为什么要使用连接池:
连接对象创建和销毁是需要耗费时间的,在服务器初始化的时候就初始化一些连接。把这些连接放入到内存中,使用的时候可以从内存中获取,使用完成之后将连接放入连接池中。从内存中获取和归还的效率要远远高于创建和销毁的效率。(提升性能)。
这里我们使用c3p0连接池 :
c3p0是一个开源的JDBC连接池.它实现了数据源和JNDI的绑定,支持JDBC3规范和JDBC2的标准扩展.
c3p0 需要引入的jar包:
c3p0-0.9.1.2.jar
- maven
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
使用连接池查询数据:
public class C3p0Demo1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1 创建池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2 设置连接数据库的参数
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/han");
dataSource.setUser("root");
dataSource.setPassword("123");
//3 获得连接
conn = dataSource.getConnection();
//4 编写SQL
String sql = "select * from orderitem";
//5 预编译sql
ps = conn.prepareStatement(sql);
//6 执行sql
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("product"));
System.out.println(rs.getDouble("price"));
}
//4. 释放资源
JDBCUtils.release(rs, ps, conn);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
c3p0的配置文件c3p0-config.xml
c3p0可以使用出c3p0-config.xml文件配置,也可以使用 .properties文件配置
创建连接池时默认去类的路径下查找一个名字叫 c3p0-config.xml 的文件.
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///han</property>
<property name="user">root</property>
<property name="password">123</property>
<!-- 默认初始化的连接数量,往连接池放5个连接-->
<property name="initialPoolSize">5</property>
<!--连接的最少数量-->
<property name="minPoolSize">5</property>
<!--连接的最大数量-->
<property name="maxPoolSize">20</property>
</default-config>
<!-- This app is massive! -->
<!-- <named-config name="oracle">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///han</property>
<property name="user">root</property>
<property name="password">123</property>
</named-config> -->
</c3p0-config>
- 连接池对象应该是一个应用只创建一次就可以的,不需要每次使用都创建一个新的连接池。所以我们要改写工具类:
public class JDBCUtils2 {
//获得连接池
private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
/**
* 返回连接池
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 获得连接
* @throws SQLException
*/
public static Connection getConnection() throws Exception{
return dataSource.getConnection();
}
/**
* 释放资源的方法
*/
public static void release(Statement stmt,Connection conn){
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs,Statement stmt,Connection conn){
// 资源释放:
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
三 JDBC的工具类库: DBUtils的概述
开源工具类库: 对JDBC的简单封装,而且没有影响性能。 因为JDBC手写比较麻烦,而且有非常多的代码是类似的。比如获得连接,预编译SQL,释放资源等..那么可以将这些代码抽取出来放到工具类中。将类似的代码进行抽取。大大简化JDBC的编程。
DBUtils需要使用的jar包:**
commons-dbutils-1.6.jar
maven
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
DBUtils的API详解:
- QueryRunner对象:核心运行类
- 在一般情况下如果执行CRUD的操作:
- 构造:
QueryRunner(DataSource ds); - 方法:
int update(String sql,Object… args);
T query(String sql,ResultSetHandler rsh,Object… args);
- 构造:
- 如果有事务管理的话使用另一套完成CRUD的操作
- 构造:
QueryRunner(); - 方法:
int update(Connection conn,String sql,Object… args);
T query(Connection conn,String sql,ResultSetHandler rsh,Object… args);
- 构造:
- 在一般情况下如果执行CRUD的操作:
增删改:
导入jar包,配置出c3p0-config.xml, JDBCUtils2工具类
这里不需要手动的释放资源,DBUtils会自动的释放资源,则JDBCUtils2工具类中的释放资源的代码就可以删掉了.
这里只写一个插入数据:
//插入数据
public void insertProduct() throws SQLException{
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
queryRunner.update("insert into orderitem values (?,?,?)",null,"电视","45.2");
}
查询
创建JavaBean :Student 类
处理结果集接口 ResultSetHandler 的实现类:
- BeanHandler : 将一条记录封装到javaBean中去 行 (常用)
@Test
public void demo1() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Student student = qr.query(" select * from user where id = ?",new BeanHandler<Student>(Student.class),2 );
System.out.println(student);
}
- BeanListHandler : 将多条记录封装到装有javaBean的List集合中去 行(常用)
@Test
/**
* 一条记录就是一个Java对象(javaBean),如果多条记录,则将多个对象装到List集合中去.
* @throws SQLException
*/
public void demo2() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
List<Student> list = qr.query("select * from user ", new BeanListHandler<Student>(Student.class));
for (Student student : list) {
System.out.println(student);
}
}
- ArrayHandler : 将一条记录封装到一个Object数组中
@Test
public void demo5() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Object[] obj = qr.query("select * from user where id = ?", new ArrayHandler(),3);
for (Object object : obj) {
System.out.println(object);
}
}
- ArrayListHandler :.将多条记录封装到一个装有Object数组的List集合中去.
ScalarHandler : 将单个值封装.
@Test
public void demo3() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Object obj = qr.query("select count(*) from user", new ScalarHandler());
System.out.println(obj);
}
- ColumnListHandler() : 将一列(字段)的值封装到List集合中 ()可以传入参数,传入的是要封装的列.
@Test
public void demo4() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
List<Object> list = qr.query("select nickname from user ", new ColumnListHandler());
for (Object obj : list) {
System.out.println(obj);
}
}
MapHandler: 将一条记录封装到一个Map集合中,Map集合的key是列名(字段名) values是表中列的记录值 //结果 {id=1, username=小张, nickname=张三, age=12, password=123}
MapListHandler : 将多条记录封装到一个装有Map集合中的List集合中
@Test
public void demo6() throws SQLException{
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
List<Map<String,Object>> list = qr.query("select * from user", new MapListHandler());
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
第一次写博客,如果有错误的地方指正