​ JDBC是为访问不同数据库提供的统一接口,为使用者屏蔽了细节问题。可以利用JDBC连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。

数据库连接方式

连接数据库主要有2种方式

  1. 使用Class.forName自动完成注册驱动,直接连接数据库:

Class.forName(“com.mysql.cj.jdbc.Driver”);

Connection connection = DriverManager.getConnection(url, user, password); //其中的参数最好在使用时从文件中提取出来,方便修改

  1. jdk1.5以后使用了jdbc4,不再需要显示调用Class.forName注册驱动,可以直接使用语句Connection connection = DriverManager.getConnection(url, info);连接数据库

在Java中输入SQL语句

在连接建立后,如果需要对数据库进行访问,执行命名或者SQL语句,可以通过Statement、PreparedStatement、CallableStatement,在开发中不会使用Statement,因为其存在SQL注入问题,一般使用PerparedStatement:

  • PreparedStatement:执行的SQL语句中的参数用问号(?)来表示,调用相应的set方法来设置对应的参数。set方法有两个参数,第一个参数要设置SQL语句中的?的参数索引(从1开始),第二个是设置SQL语句中参数的值

在使用DML语句时,直接使用String即可,在使用DQL语句时需要借助ResultSet获取结果:

  • ResultSet:保持一个光标指向其当前的数据行。最初光标位于第一行之前。next方法可以将光标移动到下一行,并且在ResultSet对象中没有更多行时返回false,所以可以用while循环遍历结果集。

演示

使用localhost的test数据库,登录root用户完成对emp表的增删改查。

public class Test{
public static void main(String[] args) throws Exception {
Properties info = new Properties(); // 从Properties文件中获取数据
info.load(new FileInputStream("src\\mysql.properties"));
String driver = info.getProperty("driver"); // com.mysql.cj.jdbc.Driver
String user = info.getProperty("user");
String password = info.getProperty("password");
String url = info.getProperty("url"); // jdbc:mysql://localhost/test
Class.forName(driver);
String insert = "insert into emp values(null, '小明', 18)"; // 增
String update = "update emp set name='小红' where id = 1"; // 改
String select = "select id from emp where name=?"; // 查
String drop = "delete from emp where id = 1"; // 删
Connection connection = DriverManager.getConnection(url, user, password); // 连接数据库
PreparedStatement preparedStatement = connection.prepareStatement(select);
preparedStatement.executeUpdate(insert);
preparedStatement.executeUpdate(update);
preparedStatement.setString(1, "小明"); // 设置第一个问号处填写的值
ResultSet resultSet = preparedStatement.executeQuery(); // 使用ResultSet获取select的返回结果
while (resultSet.next()){
int id = resultSet.getInt(1);
System.out.println(id);
}
preparedStatement.executeUpdate(drop);
preparedStatement.close(); // 关闭连接
resultSet.close();
connection.close();
}
}

JDBC处理事务

使用Connection connection = DriverManager.getConnection(url, user, password);得到数据库连接之后,可以connection.setAutoCommit(false)设置事务不自动提交,然后在正常结束的逻辑后面使用connection.commit()提交事务,如果发生了异常,使用connection.rollback()回滚事务

批处理

当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。使用批处理功能时需要在url后面加入参数?rewriteBatchedStatements=true。批处理往往和PreparedStatement一起使用。

方法

  • addBatch():添加需要批量处理的SQL语句或参数

  • executeBatch():执行批量处理语句

  • clearBatch():清空批处理的语句

连接池

传统连接的问题

  • 传统的JDBC数据库连接使用DriverManager获取,每次向数据库建立连接时都要将Connection加载到内存中,再验证IP地址,用户名和密码。频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃
  • 每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终将导致数据库重启
  • 传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,数据库崩溃。
  • 解决传统开发中的数据库连接问题,可以采用数据库连接池技术

连接池原理

  1. 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从中取出一个,使用完毕之后再放回去
  2. 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
  3. 当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中

连接池种类

  1. JDBC的数据库连接池使用javax.sql.DataSource表示,DataSource是一个接口,通常由第三方提供实现
  2. C3P0连接池,速度相对较慢,稳定性强(hibernate, spring底层使用该连接池)
  3. DBCP连接池,速度较快,不稳定
  4. Proxool数据库连接池,可以监控连接池状态,稳定性较差
  5. BoneCP数据库连接池,速度快
  6. Druid(德鲁伊)是阿里提供的连接池,集DBCP、C3PO、Proxool优点于一身的数据库连接池

C3P0连接池

要使用C3P0连接池,首先要导入C3P0的jar包,并且把jar包当做library加入到项目中

使用时:

  1. 实例化ComboPooledDataSource数据源对象
  2. 通过配置文件获取数据库相关信息
  3. 通过方法给数据源设置相关参数setDriverClasssetJdbcUrlsetUsersetPassword
  4. 设置初始化连接数(连接池中一开始的连接数量)和最大连接数(最多能有多少连接):setInitialPoolSize(n)setMaxPoolSize(n)
  5. 拿到连接:Connection connection = comboPooledDataSource.getConnection()

Druid连接池

  1. 首先配置Properties文件,在文件中写明driver、url、user、password、initialSize、minIdle、maxActive、maxWait参数
  2. 创建指定参数的数据库连接池DataSource ds = DruidDataSourceFactory.createDataSource(properties)
  3. 拿到连接:Connection connection = ds.getConnection()

ApDBUtils

commons-dbutils是一个JDBC工具类库,可以极大简化jdbc编码的工作量。

DbUtils类

  • QueryRunner类:封装了SQL的执行,可以实现增删改查和批处理操作,线程安全
  • ResultSetHandler:用于出来ResultSet,按照数据要求转换成另一种形式
    • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中
    • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里
    • ScalarHandler:查询单行单列信息时,将该信息包装成一个Object对象返回
    • update:执行增删改操作,返回受影响的行数

用法

首先导入commons-dbutils.jar包,然后才能使用其提供的方法。

public class Test{
public static void main(String[] args) throws Exception {
Properties data = new Properties();
data.load(new FileInputStream("src\\druid.properties")); // 从文件中读取driver、url、user、password
DataSource ds = DruidDataSourceFactory.createDataSource(data); // 创建德鲁伊数据源对象
Connection connection = ds.getConnection(); · // 获取连接
QueryRunner queryRunner = new QueryRunner();
String select = "select * from emp where id >= ?";
String update = "update emp set name = ? where id = ?";
String insert = "insert into emp values(null, ?, ?)";
String update = "delete from emp where id = ?";
// query执行sql语句,得到resultset并封装到ArrayList中,需要传入connection、sql语句、BeanListHandler对象, 最后的数字是给?赋值,可以有多个
List<Actor> list = queryRunner.query(connection, select, new BeanListHandler<>(Actor.class), 1);
// 执行DML语句使用update方法,传入连接,sql和需要赋值的?
int rows = queryRunner.update(connection, update, "小明", 2);
rows = queryRunner.update(connection, insert, "小白", 21);
rows = queryRunner.update(connection, drop, 3);
for(Actor a: list){
System.out.println(a.toString());
}
connection.close(); // 只需要关闭connection,resultset和perparedStatement由queryRunner自动关闭
}
}