传统连接获取Connection存在的问题
1)传统的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接都需要将Connection加载到内存中,再验证IP地址、用户名和密码,频繁的进行数据库连接操作将占用非常多的系统资源,容易造成服务器崩溃;
2)数据库连接使用完后都必须断开连接释放资源,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终导致重启数据库;
3)传统获取连接的方式 不能控制创建的连接数量,如果连接过多也可能导致内存泄漏致使MySQL数据库崩溃;
4)解决传统开发中的数据库连接问题可以采用数据库连接池技术(connection pool)。
数据库连接池基本介绍
1)预先在缓冲池中放入一定数量的链接,当需要建立数据库连接时,只需要从“缓冲池”中取出,使用完毕后再“放回”;
2)数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立;
3)当应用程序向连接池请求的连接数量超过最大连接数量时,这些请求将被加入到等待队列中。
通过连接池链接数据库步骤
1)从连接池取出连接;
2)使用链接,操作SQL语句;
3)连接放回连接池(程序对连接的引用断开,连接依然可以重复使用)。
如果当前连接都被占用,则新的待连接程序进入等待队列。
数据库连接池种类
1)JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现;
2)C3P0数据库连接池,速度相对较慢但是稳定性比较好(hibernate,spring都采用该连接池);
3)DBCP数据库连接池,速度相对C3P0较快,但稳定性较差;
4)Proxool数据库连接池,有监控链接池状态的功能,稳定性相对于C3P0差一些;
5)BoneCP数据库连接池,速度快;
6)Druid(德鲁伊)是Alibaba提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池。
C3P0测试代码
package com.pero.datasource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import java.beans.PropertyVetoException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: C3P0_
* @date 2022/10/28 22:48
*/
public class C3P0_ {
//使用方法一:在程序中指定相关参数(user、url、password)
@Test
public void testC3P0_01() throws IOException, PropertyVetoException, SQLException {
//1.创建数据源对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//2.通过配置文件mysql.properties获取相关信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//3.获取相关属性
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//4.给数据源comboPooledDataSource设置相关参数(连接管理交给数据源comboPooledDataSource)
comboPooledDataSource.setDriverClass(driver); //设置连接数据库驱动
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setPassword(password);
//5.设置初始化连接数和连接数上限
comboPooledDataSource.setInitialPoolSize(10); //初始化连接数
comboPooledDataSource.setMaxPoolSize(50); //连接数上线
//6.获取链接
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("连接数据库5000次用时:" + (end - start));
}
//使用方法二:使用配置文件模板来完成
@Test
public void testC3P0_02() throws SQLException {
//1.先导入c3p0-config.xml文件src目录下
//2.该文件指定了连接数据库和连接池的相关参数
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("myc3p0");
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("连接数据库5000次耗时:" + (end - start));
}
}
<c3p0-config>
<named-config name="myc3p0">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- url -->
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/pero_db01</property>
<!-- 用户名 -->
<property name="user">root</property>
<!-- 密码 -->
<property name="password">pero</property>
<!-- 每次增长的连接数 -->
<property name="acquireIncrement">5</property>
<!-- 初始连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">50</property>
<!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property>
<!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
Druid测试代码
package com.pero.datasource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.Test;
import org.junit.jupiter.api.TestInstance;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: Druid_
* @date 2022/10/28 22:57
*/
public class Druid_ {
//添加Druid的jar包和相关配置文件
@Test
public void testDruid() throws Exception {
//创建properties对象,读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));
//创建指定参数的数据库连接池(德鲁伊连接池)
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
long start = System.currentTimeMillis();
//建立连接
for (int i = 0; i < 5000; i++) {
Connection connection = dataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("数据库连接耗时:" + (end - start));
}
}
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/pero_db01?rewriteBatchedStatements=true
#url=jdbc:mysql://127.0.0.1:3306/pero_db01
username=root
password=pero
#initial connection size
initialSize=10
#min idle connection size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000
德鲁伊工具类
package com.pero.datasource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mysql.jdbc.ResultSetRow;
import com.sun.corba.se.spi.ior.IdentifiableFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: JDBCUtilsByDruid
* @date 2022/10/29 22:33
*/
public class JDBCUtilsByDruid {
private static DataSource ds;
//在静态代码块中对ds初始化
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取connection
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//关闭资源,将连接放回连接池
public void close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet != null){
resultSet.close();
}
if (statement != null){
statement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
测试代码
package com.pero.datasource;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: JDBCUtilsByDruid_Use
* @date 2022/10/29 23:30
*/
public class JDBCUtilsByDruid_Use {
@Test
public void testUseDruid(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = "insert into admin values (?,?)";
try {
connection = JDBCUtilsByDruid.getConnection(); //com.alibaba.druid.pool.DruidPooledConnection
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"pero");
preparedStatement.setInt(2,951357);
preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,preparedStatement,connection);
}
}
@Test
public void testSelect(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = "select * from admin";
try {
connection = JDBCUtilsByDruid.getConnection();
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
String name = resultSet.getString("name");
int password = resultSet.getInt("password");
System.out.println(name + "\t" + password);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(resultSet,preparedStatement,connection);
}
}
}
Apache-DBUtils
问题分析
1)关闭connection后,resultSet结果集无法使用;
2)resultSet不利于数据管理
3)示意图
MySQL数据库 | ← | java程序 1.得到链接 2.发送SQL指令 | 意义: 相当于将表中的数据信息与ArrayList集合相对应的保存 | |
→ | 返回resultSet 存在问题 1.结果集和connection是关联的,如果关闭连接则不能再使用结果集; 2.结果集不利于数据管理【只能使用一次】; 3.使用返回信息不方便。 | → | 将结果集记录,封装到ArrayList<数据表类名> | |
数据表信息 | ↔ | Java类==>(JavaBean,PoJO,Domain) class Test { //属性 private int id; private String name; ... //无参构造器 //带参构造器 //Getter And Setter } | → | ↑ 一个表数据对象对应一条表记录,表对象放入到ArrayList集合 |
方法演示测试代码
package com.pero.datasource;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: JDBCUtilsByDruid_Use
* @date 2022/10/29 23:30
*/
public class JDBCUtilsByDruid_Use {
//将ResultSet封装到ArrayList集合中
@Test
public void testSelectToArrayList() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String sql = "select * from admins";
ArrayList<Admins> adminsArrayList = new ArrayList<>();
try {
connection = JDBCUtilsByDruid.getConnection();
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String user_name = resultSet.getString("user_name");
String password = resultSet.getString("password");
//把得到的resultSet信息封装到Admins对象,然后放入到ArrayList集合中
Admins admins = new Admins(id, user_name, password);
adminsArrayList.add(admins);
}
for (Admins admins : adminsArrayList) {
System.out.println(admins.getId() + "\t" + admins.getName() +
"\t" + admins.getPassword());
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(resultSet,preparedStatement,connection);
}
//因为ArrayList与connection没有任何关联,该集合可以复用
//return list;
}
}
package com.pero.datasource;
/**
* @author Pero
* @version 1.0
* @title: Admins
* @date 2022/10/30 22:02
*/
public class Admins {
private Integer id;
private String user_name;
private String password;
public Admins() { //一定要给一个无参构造器【反射需要】
}
public Admins(Integer id, String user_name, String password) {
this.id = id;
this.user_name = user_name;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return user_name;
}
public void setName(String user_name) {
this.user_name = user_name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Admins{" +
"id=" + id +
", user_name='" + user_name + '\'' +
", password='" + password + '\'' +
'}';
}
}
Apache-DBUtils基本介绍
1)commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的封装,使用dbutils能极大简化jdbc编码的工作量;
DbUtils类
1)QueryRunner类:该类封装了SQL的的执行,并且是线程安全的,可实现增删改查、批处理;
2)使用QueryRunner类实现查询;
3)ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按照要求转换为另一种形式。
ArrayHandler: | 把结果集中的第一行数据转换成对象数组; |
ArrayListHandler: | 把结果集中的每一行数据都转成一个数组,再存放到List中; |
BeanHandler: | 将结果集中的第一行数据封装到一个对应的JavaBean实例中; |
BeanListHandler: | 将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List中; |
ColumnListHandler: | 将结果集中某一列的数据存放到List中; |
KeyedHandler(name): | 将结果集中的每一行数据都封装到一个Map里(List<Map>),再把这些map再存到一个map里,其key为指定的列; |
MapHandler: | 将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值; |
MapListHandler: | 将结果集中的每一行数据都封装到一个Map中,然后再存放到List中; |
ScalarHandler: | 获取结果集中第一行数据指定列的值,常用来进行单值查询。 |
测试代码1
package com.pero.datasource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @author Pero
* @version 1.0
* @title: DBUtils_USE
* @date 2022/10/31 16:52
*/
public class DBUtils_USE {
//使用apache-DBUtils 工具类 + druid完成对表的crud操作
@Test
//使用apache-dbUtils + druid查询多条语句
public void testQueryMany() throws SQLException { //返回结果为多行数据
//获取链接
Connection connection = JDBCUtilsByDruid.getConnection();
String sql = "select * from admins where id >= ?";
//使用DBUtils类和接口,先引入DBUtils相关jar文件,并导入到该项目中
//创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
//使用queryRunner对象的方法返回ArrayList结果集
//query()方法通过连接并执行sql语句,得到一个结果集ResultSet并封装到ArrayList集合中,并返回集合
//connection:连接;
// sql:执行的sql语句;
//BeanListHandler查询多条语句
//new BeanListHandler<>(Admins.class):将ResultSet取出存放到Admins对象中然后封装到ArrayList中
//Admins.class:底层利用反射机制查看Admins类中有哪些属性,来进行封装操作;
//1:该位置是可变形参,可以传入多个参数,该参数是给sql语句中的?赋值;
//ResultSet和PrepareStatement会在query()方法中进行了关闭
List<Admins> query =
queryRunner.query(connection, sql, new BeanListHandler<>(Admins.class), 1);
for (Admins admins : query) {
System.out.println(admins);
}
//释放资源
JDBCUtilsByDruid.close(null,null,connection);
}
@Test
//使用apache-dbUtils + druid查询一条语句
public void testQuerySingle() throws SQLException {
Connection connection = JDBCUtilsByDruid.getConnection();
String sql = "select * from admins where id = ?";
QueryRunner queryRunner = new QueryRunner();
//查询单行记录,返回单个对象,使用的Handler是BeanHandler
Admins query =
queryRunner.query(connection, sql, new BeanHandler<>(Admins.class), 1);
System.out.println(query);
JDBCUtilsByDruid.close(null,null,connection);
}
//使用apache-dbUtils + druid 查询单行单列-返回一个Object对象
@Test
public void testScalar() throws SQLException {
Connection connection = JDBCUtilsByDruid.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "select user_name from admins where id = ?";
Object object = queryRunner.query(connection, sql, new ScalarHandler<>(), 3);
System.out.println(object);
JDBCUtilsByDruid.close(null,null,connection);
}
//使用apache-dbUtils + druid 完成DML(delete、insert、update)
@Test
public void testDML() throws SQLException {
Connection connection = JDBCUtilsByDruid.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql_update = "update admins set password = ? where user_name = ?";
String sql_insert = "insert into admins values (null,?,?)";
String sql_delete = "delete from admins where id = ?";
//执行DML操作调用queryRunner的update()方法,返回值为受影响的行数
//int affectedRow = queryRunner.update(connection, sql_update, 213546, "jack0");
//int affectedRow01 = queryRunner.update(connection, sql_insert, "lucy", 123456);
int affectedRow02 = queryRunner.update(connection, sql_delete, 5);
//System.out.println(affectedRow > 0 ? "成功" : "执行没有影响到表");
//System.out.println(affectedRow01 > 0 ? "执行成功" : "执行没有影响到表");
System.out.println(affectedRow02 > 0 ? "执行成功" : "执行结果没有影响到表");
JDBCUtilsByDruid.close(null,null,connection);
}
}
源码分析
private <T> T query(Connection conn/*连接对象*/, boolean closeConn/*是否关闭连接*/, String sql/*sql命令*/, ResultSetHandler<T> rsh/*结果集的对象的集合*/, Object... params/*sql命令中对应?位置的值*/) throws SQLException {
if (conn == null) { //判断传入的连接对象是否为null,如果为null抛出Null connection连接异常
throw new SQLException("Null connection");
} else if (sql == null) { //判断语句是否为空,如果为空则进行下一组判断
if (closeConn) { //判断closeConn是否为true,如果为true则关闭连接
this.close(conn);
}
throw new SQLException("Null SQL statement"); //抛出Null SQL statement异常
} else if (rsh == null) { //判断接收的集合对象是否为null
if (closeConn) { //判断closeConn是否为true,如果为true则关闭连接
this.close(conn);
}
throw new SQLException("Null ResultSetHandler"); //抛出Null ResultSetHandler异常
} else {
PreparedStatement stmt = null; //定义preparedStatement、ResultSet、T引用
ResultSet rs = null;
T result = null;
try {
stmt = this.prepareStatement(conn, sql); //将preparedStatement对象传给stmt
this.fillStatement(stmt, params); //将params的值赋值给预处理对象stat中sql语句的问号
rs = this.wrap(stmt.executeQuery()); //执行sql语句返回结果集,并将结果集resultSet对象经过处理后传给rs
result = rsh.handle(rs); //将结果集经过处理(使用到了反射机制获取Admins类中的信息对结果集进行封装)传入rsh(ArrayList集合)并指向result引用
} catch (SQLException var33) {
this.rethrow(var33, sql, params); //异常抛出
} finally { //资源关闭
try {
this.close(rs);
} finally {
this.close(stmt);
if (closeConn) {
this.close(conn);
}
}
}
return result; //返回结果
}
}
数据表和JavaBean的类型映射关系
int,double等类型在Java中都必须用包装类,因为mysql中的所有类型都可能是null,而Java中只有引用类型才有null值;
表 | JavaBean |
int(11) | Integer |
varchar(32),char(1) | String |
double | Double |
date | Date |
BasicDAO(date access object数据访问对象)
apache-dbutils + Druid 虽然简化了JDBC开发,但依旧存在着不足:
1)SQL语句是固定的,不能通过参数传入,通用性不足,进行改进以便更好执行增删改查命令;
2)对于select操作,如果有返回值,则返回类型不能固定,需要使用泛型;
3)对于众多的数据表和复杂的业务需求,不可能只靠一个Java类来完成;
4)BasicDAO示意图:
TestDAO 1.根据业务需求使用对应的DAO; 2.职能划分各司其职,业务设计清晰。 | ||
调↓用 | ||
AppView 1.界面层; 2.调用service层的相关类,得到结果显示数据。 | ||
调↓用 | ||
ActorService/GoodsService/OrderService 1.业务层; 2.组织sql命令,并调用相应的XxxDAO,完成综合需求。 | ||
调↓用 | ||
DAO BasicDAO 1.将各类DAO共同的代码归类到BasicDAO; 2.简化代码,提高维护性和可读性。 | ||
继↑承 | ||
ActorDAO 完成对actor表的增删改查操作 可以有特有操作 | GoodsDAO 完成对goods表的增删改查操作 可以有特有操作 | OrderDAO 完成对order表的增删改查操作 可以有特有操作 |
操↓作 | 操↓作 | 操↓作 |
MySQL | ||
actor表 | goods表 | order表 |
关↑联 | 关↑联 | 关↑联 |
JavaBean | ||
Actor类 [JavaBean,domain,pojo] | Goods类 [JavaBean,domain,pojo] | Order类 [JavaBean,domain,pojo] |
基本介绍
1)通用类BasicDAO是专门与数据库交互的,用以完成对数据库(表)的增删改查操作;
2)在BasicDAO的基础上实现一张表对应一个DAO,例如Actor表-Actor.java类(JavaBean)-ActorDAO.java。
BasicDAO应用设计
1)创建com.pero.dao_包;
2)在com.pero.dao_包下创建utils工具包,存放工具类;
JDBCUtilsByDruid类
package com.pero.dao_.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: JDBCUtilsByDruid
* @date 2022/10/29 22:33
*/
public class JDBCUtilsByDruid {
private static DataSource ds;
//在静态代码块中对ds初始化
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取connection
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//关闭资源,将连接放回连接池
public static void close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet != null){
resultSet.close();
}
if (statement != null){
statement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
3)在com.pero.dao_包下创建domain包,存放JavaBean文件;
Actor类
package com.pero.dao_.domain;
import java.util.Date;
/**
* @author Pero
* @version 1.0
* @title: Actor
* @date 2022/11/5 17:25
*/
public class Actor {
/**
* 数据库中actor表的列属性
*/
private Integer id;
private String name;
private String sex;
private Date date;
private Integer phone;
/**
* 空构造器,方便反射使用
*/
public Actor() {
}
/**
* 全属性构造器
*/
public Actor(Integer id, String name, String sex, Date date, Integer phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.date = date;
this.phone = phone;
}
/**
* Setter and Getter
*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Integer getPhone() {
return phone;
}
public void setPhone(Integer phone) {
this.phone = phone;
}
/**
* toString
*/
@Override
public String toString() {
return "Actor{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", date=" + date +
", phone=" + phone +
'}';
}
}
4)在com.pero.dao_包下创建dao包,存放XxxDAO和BasicDAO类;
BasicDAO类
package com.pero.dao_.dao;
import com.pero.datasource.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import javax.lang.model.element.VariableElement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @author Pero
* @version 1.0
* @title: BasicDAO
* @date 2022/11/5 17:48
*/
public class BasicDAO<T> { //指定具体类型
private QueryRunner queryRunner = new QueryRunner();
Connection connection = null;
/*
* 功能描述: <增删改操作>
* <>
* @Param: [sql,parameters]
* @Return: int
* @Author: pero
* @Date: 2022/11/6 12:41
*/
public int update(String sql, Object...parameters){
try {
connection = JDBCUtilsByDruid.getConnection();
int update = queryRunner.update(connection,sql, parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
/*
* 功能描述: <返回多个对象(多行查询结果),针对任意表>
* <end>
* @Param: [sql, clazz, parameters]
* @Return: java.util.List<T>
* @Author: pero
* @Date: 2022/11/5 20:27
*/
public List<T> queryMultiply(String sql, Class<T> clazz, Object... parameters){
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection, sql, new BeanListHandler<T>(clazz), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
/*
* 功能描述: <查询单行结果>
* <end>
* @Param: [sql, clazz, parameters]
* @Return: T
* @Author: pero
* @Date: 2022/11/5 20:45
*/
public T querySingle(String sql, Class<T> clazz, Object...parameters){
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection, sql, new BeanHandler<T>(clazz), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
/*
* 功能描述: <查询单行单列的方法,返回单值>
* <>
* @Param: [sql,parameters]
* @Return: [Object]
* @Author: pero
* @Date: 2022/11/5 20:58
*/
public Object queryScalar(String sql, Object...parameters){
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql, new ScalarHandler(), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
}
ActorDAO类
package com.pero.dao_.dao;
import com.pero.dao_.domain.Actor;
/**
* @author Pero
* @version 1.0
* @title: ActorDAO
* @date 2022/11/6 12:53
*/
public class ActorDAO extends BasicDAO<Actor>{
//具有BasicDAO所有的方法
//根据业务需求编写特有方法
}
5)在com.pero.dao_包下创建test包,存放测试类。
package com.pero.dao_.test;
import com.pero.dao_.dao.ActorDAO;
import com.pero.dao_.domain.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
/**
* @author Pero
* @version 1.0
* @title: TestDAO
* @date 2022/11/6 12:55
*/
public class TestDAO {
//测试actor表的增删改查操作
@Test
/*
* 功能描述: <多行查询>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 14:18
*/
public void testActorSelectForMultiply(){
ActorDAO actorDAO = new ActorDAO();
List<Actor> actors =
actorDAO.queryMultiply("select * from actor where id > ?", Actor.class, 3);
for (Actor actor : actors) {
System.out.println(actor);
}
}
@Test
/*
* 功能描述: <单行查询>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 14:26
*/
public void testActorSelectForSingle(){
ActorDAO actorDAO = new ActorDAO();
Actor actor =
actorDAO.querySingle("select * from actor where id = ?", Actor.class, 5);
System.out.println(actor);
}
@Test
/*
* 功能描述: <单行单列查询>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 14:32
*/
public void testActorSelectForScalar(){
ActorDAO actorDAO = new ActorDAO();
Object scalar =
actorDAO.queryScalar("select name from actor where id = ?", 4);
System.out.println(scalar);
}
@Test
/*
* 功能描述: <添加数据>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 18:16
*/
public void testActorInsertForUpdate() throws IOException {
ActorDAO actorDAO = new ActorDAO();
Properties properties = new Properties();
properties.load(new FileInputStream("src\\actorFile.properties"));
String name = properties.getProperty("name");
String sex = properties.getProperty("sex");
String borndate = properties.getProperty("borndate");
String phone = properties.getProperty("phone");
int update =
actorDAO.update("insert into actor values (null,?,?,?,?)",name,sex,borndate,phone);
System.out.println(update > 0 ? "数据添加成功" : "添加操作未对数据库表产生影响");
}
@Test
/*
* 功能描述: <修改数据>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 18:57
*/
public void testActorUpdateForUpdate() throws IOException {
ActorDAO actorDAO = new ActorDAO();
Properties properties = new Properties();
properties.load(new FileInputStream("src\\actorFile.properties"));
String name = properties.getProperty("name");
String sex = properties.getProperty("sex");
String borndate = properties.getProperty("borndate");
String phone = properties.getProperty("phone");
int update =
actorDAO.update("update actor set name = ?, sex = ?, borndate = ?, phone = ? where id = ?", name, sex, borndate, phone, 5);
System.out.println(update > 0 ? "修改成功" : "操作语句未对表产生影响");
}
@Test
/*
* 功能描述: <删除指定行数据>
* <>
* @Param: []
* @Return: void
* @Author: pero
* @Date: 2022/11/6 19:03
*/
public void testActorDeleteForUpdate(){
ActorDAO actorDAO = new ActorDAO();
int update =
actorDAO.update("delete from actor where id = ?", 6);
System.out.println(update > 0 ? "删除成功" : "操作语句未对表产生影响");
}
}
actorFile.properties
name=marry
sex=woman
borndate=2002-05-31
phone=136656326