JDBC和数据库连接池
一.JDBC
1.JDBC介绍
Java厂商制定规范的一套接口(jdbc),由各个数据库厂商实现(jdbc驱动),当我们用Java访问数据库时,只需要导入对应厂商提供的驱动jar包,然后使用程序调用接口中的方法即可。
jdbc是java提供的一套用于数据库操作的接口API,不同的数据库厂商需要针对这套接口提供不同的实现,Java程序猿只需要面向这套接口编程即可。
2.应用-得到连接:
2.1 new一个properties对象
2.2调用这个propertoes对象的load方法,传入一个FileInputStream对象,获取到配置文件。优点:使用配置文件,让连接 mysql 更加灵活
2.3调用这个propertoes对象的getProperty方法得到文件中的信息
2.4 DriverManager.getConnection方法实现获取连接,其中DriverManager 替代 driver 进行统一管理,在底层使用反射加载了 Driver 类,在加载 Driver 类时,完成注册(静态代码块实现)。
//通过 Properties 对象获取配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
Class.forName(driver);//写上
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println( connection);
3.应用-执行语句
3.1 Statement接口
在得到连接之后,我们想要执行sql语句,此时java设计了Statement接口来实现。
Statement statement = connection.createStatement()得到一个statement对象后:
statement.executeUpdate(sql)执行dml语句
statement.executeQuery(sql)执行dql语句,该执行的结果需要对象来接收,java设计者设计了ResultSet[结果集]来接收。
3.2 PreparedStatement接口
引入:statement由于statement.executeQuery(sql)执行语句直接使用sql,这个sql是直接输入的,没有经过预处理,会有sql注入的问题存在,相当危险,所以出现了PreparedStatement解决这一问题。
优点:预处理了减少了编译次数,效率up;有效的解决了sql注入问题
总结:之后我们就使用PreparedStatement接口来执行操作了。
4.应用-得到结果
4.1ResultSet[结果集] 概念:表示数据库结果集的数据表,通常执行查询数据库语句时生成
4.2重要方法:resultSet.next();向下移动一行,无则返回false
resultSet.previous()向上移动一行,无则false
getXXX;getObject;
String sql = "select name , pwd from admin where name =? and pwd = ?";
// preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 给 ? 赋值
preparedStatement.setString(1, admin_name);
preparedStatement.setString(2, admin_pwd);
// 执行 select 语句使用 executeQuery
// 执行的是 dml(update, insert ,delete) executeUpdate()
ResultSet resultSet = preparedStatement.executeQuery();
5.事务
jdbc中当一个connection被创建时,默认是自动提交事务:执行完sql语句自动commit,无法回滚。而jdbc为了让多个sql语句作为整体执行,需要使用事务。
connection.setAutoCommit(false); //开启事务
connection.commit();//提交
connection.rollback();//回滚
6.批处理
使用批处理解决大量sql语句每次通过流对象传输(一条一条的传输)而带来的时间问题
批处理提供了Batch,将sql语句存入其中,打包批量处理,减少了运行次数,提升了效率。
preparedStatement.addBatch();
preparedStatement.executeBatch();
preparedStatement.clearBatch();

二.数据库连接池
1.引入:Java程序连接数据库时,如果数量太多又没有受到控制,可能会挤爆数据库(内存泄漏),而且每个Java程序使用时获取与使用完成后断开连接,都是实在实在与数据库交互,时间耗费大
2.解决问题:数据库连接池技术,在缓冲池中设立一定数量的连接,Java程序使用时获取使用完成后释放拿取的连接到池中,过程中程序与数据库、连接与数据库没有断开的过程,只是程序拿放连接,大大节省了时间。同时,通过在连接池设计等待队列,让超过池中数量的请求等待,避免了过多的请求连接导致的内存泄漏问题。
3.使用实例:C3P0(经典)、Druid(新秀,集稳定,速度,可监控优点于一体,建议使用!)
C3P0:也可以使用配置文件模板来完成
//1. 将 c3p0 提供的 c3p0.config.xml 拷贝到 src 目录下 //
2. 该文件指定了连接数据库和连接池的相关参数
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("zitWang");
这里构造器中传入的是数据源(这个连接池的name)在c3p0.config.xml 文件中查找与修改。

//1. 创建一个数据源对象 ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); //2. 通过配置文件 mysql.properties 获取相关连接的信息 Properties properties = new Properties(); properties.load(new FileInputStream("src\\mysql.properties")); //读取相关的属性值 String user = properties.getProperty("user"); String password = properties.getProperty("password"); String url = properties.getProperty("url"); String driver = properties.getProperty("driver"); //给数据源 comboPooledDataSource 设置相关的参数 //注意:连接管理是由 comboPooledDataSource 来管理 comboPooledDataSource.setDriverClass(driver); comboPooledDataSource.setJdbcUrl(url); comboPooledDataSource.setUser(user); comboPooledDataSource.setPassword(password); //设置初始化连接数 comboPooledDataSource.setInitialPoolSize(10); //最大连接数 comboPooledDataSource.setMaxPoolSize(50); //连接池获取连接 Connection connection = comboPooledDataSource.getConnection(); //这个方法就是从 DataSource 接口实现的
Druid(新秀,集稳定,速度,可监控优点于一体,建议使用!)
1.> 加入 Druid jar 包
2.>加入 配置文件 druid.properties , 将该文件拷贝项目的 src 目录
3.>创建 Properties 对象, 读取配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("src\\druid.properties"));
4.> 创建一个指定参数的数据库连接池, Druid 连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
5.>得到连接Connection connection = dataSource.getConnection()
4.Apache—DBUtils
问题:解决关闭connnection后,得到的结果集无法使用的问题,而且原来的结果集不利于数据的管理,使用其中的数据要调getxxx方法。
应对:将得到的结果集记录下来,封装到一个ArrayList<类对象>集合中,其中类对象是我们在java中根据查询的结果集对应的字段属性所创建的类,会提供有参无参构造器,get,set方法。
当我们得到结果集时,将表的每一条记录封装到对应的一个类对象中,再将类对象放入ArrayList<类对象>集合即可。
此时,Apache组织提供了一个开源的jdbc工具库类commons-dbutils

1.QueryRunner:封装了SQL的执行并且,并且是线程安全的(应该使用了事务),,可以实现curd,批处理操作
2.ResultSetHandler接口:处理结果集,将数据按照要求转化为另一种形式。
三.应用实际开发-升级版本
DBC和数据库连接池整合应用-最终版本(DBUtils工具类 +Druid连接池实现数据库的连接与CURD操作,以后开发就用这套啦 )
1.返回多行记录
返回多行记录使用BeanListHandler<>(类.class)接收resultset结果集
//1. 得到 连接 (druid)
Connection connection = JDBCUtilsByDruid.getConnection();
//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
//3. 创建 QueryRunner
QueryRunner queryRunner = new QueryRunner();
//4. 就可以执行相关的方法,返回 ArrayList 结果集
//String sql = "select * from student where id >= ?";
// sql 语句当然也可以查询部分列 比如String sql = "select id, name from actor where id >= ?";
List<Student> list =queryRunner.query(connection, sql, new BeanListHandler<>(Student.class), 1);
//(1) query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中
//(2) 返回集合
//(3) connection: 连接
//(4) sql : 执行的 sql 语句
//(5) new BeanListHandler<>(Student.class): 在将 resultset -> Student 对象 -> 封装到 ArrayList
// 底层使用 <<反射机制 >>去获取 Student类的属性,然后进行封装
//(6) 1 就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数 Object... params
//(7) 底层得到的 resultset ,会在 query 关闭, 关闭 PreparedStatment
System.out.println("输出集合的信息");
for (Student student : list) {
System.out.print(student);
}
//释放资源
JDBCUtilsByDruid.close(null, null, connection)
2.返回单行
这里使用的Hander 是 BeanHandler
Student student = queryRunner.query(connection, sql, new BeanHandler<>(Student.class), 10);
System.out.println( student);
3.返回单行单列
因为返回的是一个对象, 使用的 handler 就是 ScalarHandler
Object obj = queryRunner.query(connection, sql, new ScalarHandler(), 4);
4.dml操作
//1. 得到 连接 (druid)
Connection connection = JDBCUtilsByDruid.getConnection();
//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
//3. 创建 QueryRunner
QueryRunner queryRunner = new QueryRunner();
//4. 这里组织 sql 完成 update, insert delete
//String sql = "update student set name = ? where id = ?";
//String sql = "insert into student values(null, ?, ?, ?, ?)";
String sql = "delete from student where id = ?";
//(1) 执行 dml 操作是 queryRunner.update()
//(2) 返回的值是受影响的行数 (affected: 受影响)
//int affectedRow = queryRunner.update(connection, sql, "问号对应的内容");
// 释放资源
JDBCUtilsByDruid.close(null, null, connection);
四.DAO 和增删改查通用方法-BasicDao
当我们的查询结果涉及到多张表是,或者说我们要对很多表的ResultSet进行读取时,就会有很多个类来提供表的字段对应的类对象,然后填充到ArrayList<>集合中去,那么这种情况下,我们引出DAO
DAO:data access Object:访问数据的对象
数据库中的xx表--------------对应的domain/javabean/pojo(xx类)
xxDAO:完成对xx表的curd操作,可以有特有操作
此时由于xxDAO不止有一个,java设计思想告诉我们(高内聚,低耦合)我们可以将各个DAO的基本操作提取出来,做成一个BasicDao类作为所有xxDAO类的父类,减少代码冗余。
到此,我大概形成了一个结构,由表入深(待完善):
APPView 界面层,调用服务,得到结果,显示数据
Service 业务层,组织sql,调用xxDAO完成需求
DAO dao层 BasicDao与各个xxDao
Mysql 数据层(对应的domain/javabean/pojo(xx类)与utils工具)

浙公网安备 33010602011771号