JDBC和连接池
概述
- JDBC 为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节的问题
- Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,完成对数据库的操作
原理图
入门
JDBC前置准备步骤:
- 项目里新建目录,命名自定义
- 将.jar包拷贝到该目录,并将.jar文件加入到项目
- 右键文件 - Add as Library - OK
JDBC编写步骤:
- 注册驱动 - 加载Driver类
- 获取链接 - 得到Connection
- 执行增删改查 - 发送sql给MySQL执行
- DML - 返回影响行数
- DQL - 返回ResultSet对象
- 释放资源 - 关闭相关连接
例子:
import com.mysql.jdbc.Driver
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.注册驱动
Driver driver = new Driver();
//2.得到connection
// (1)jdbc:mysel:// 固定写法,通过jdbc 的方式连接MySQL
// (2)localhost 主机,可以是ip地址
// (3)3306 表示MySQL监听的端口
// (4)zzz_db01 连接到MySQL dbms的数据库
// (5)MySQL的连接本质就是Socket连接
String url = "jdbc:mysel://localhost:3306/zzz_db01";
//将用户名,密码放入Properties对象
Properties properties = new Properties();
//user 和 password 传参是规定好的
properties.setProperty("user","root"); //用户名
properties.setProperty("password","zzz"); //密码
Connection connect = driver.connect(url, properties);
//3.执行SQL
String sql = "insert into actor values (null, '刘得话', '男', '1970-1-1', '110')";
//statement 用于执行静态SQL语句,并返回生成的结果和对象
Statement statement = connect.createStatement();
//DML返回受影响的行数,大于0则成功
int i = statement.executeUpdate(sql);
//4.关闭资源
statement.close();
connect.close();
}
}
连接数据库的五种方式
1.获取Driver实现类对象
如上方(入门:例子)代码
2.反射机制 ,动态加载,更加灵活,减少依赖性
import com.mysql.jdbc.Driver
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class cls = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) cls.getDeclaredConstructor().newInstance();
}
}
3.DriverManager替换Driver统一管理
import com.mysql.jdbc.Driver
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class cls = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) cls.getDeclaredConstructor().newInstance();
String url = "";
String user = "";
String password = "";
DriverManager .registerDriver(driver);//注册驱动
Connection connection = DriverManager.getConnection(url,user,password);
}
}
4.Class.forName Driver静态代码自动完成注册驱动,简化代码(开发中经常使用)
import com.mysql.jdbc.Driver
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.使用反射加载Driver类
// 在加载Driver类时,Driver的静态代码也加载了
// 静态代码完成了注册工作,则完成注册
Class.forName("com.mysql.jdbc.Driver");
String url = "";
String user = "";
String password = "";
Connection connection = DriverManager.getConnection(url,user,password);
}
}
5.在方式4的基础上使用配置文件,连接数据库更加灵活
![](https://img-blog.csdnimg.cn/861f569a90ad49fea549842c2556f597.png)
package JDBC_study;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//通过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");
//传入参数
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, password);
}
}
API
DriverManager
驱动管理类,getConnection(url,user,pwd) 获取到连接
Statement(存在SQL注入)
查询语句如下,需要输入账号密码
select * from admin where user= ' ' and pwd = ' ';
SQL注入:当输入的内容为
user:1' or
pwd: or '1'='1
则where条件筛选永远成立,注入成功,能获取到其他的数据
select * from admin where user= ' 1' or ' and pwd = ' or '1'='1 ';
PerparedStatement
预处理,防止SQL注入
使用预处理的方法connection.getPreparedStatement(sql),可以防止直接传参导致SQL注入
package JDBC_study;
import com.mysql.jdbc.Driver
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.使用反射加载Driver类
// 在加载Driver类时,Driver的静态代码也加载了
// 静态代码完成了注册工作,则完成注册
Class.forName("com.mysql.jdbc.Driver");
String url = "root";
String user = "zzz";
String password = "jdbc:mysel://localhost:3306/zzz_db01";
Connection connection = DriverManager.getConnection(url,user,password);
Scanner scanner = new Scanner(System.in);
//获取输入的值
String userId = scanner.nextLine();
String pwd = scanner.nextLine();
//组织sql语句,语句的 ? 相当于占位符
String sql = "select name, id, age where user = ? and pwd = ?";
//PreparedStatement对象实现了PreparedStatement接口的实现类的对象
PreparedStatement preparedStatement = connection.getPreparedStatement(sql);
//给 ? 占位符赋值
preparedStatement.setString(1,userId);
preparedStatement.setString(2,pwd);
//因为上方已经预处理了sql语句,且赋值了,所以此处执行sql的方法就不需要传参了
preparedStatement.executeQuery();
}
}
DML预处理
package JDBC_study;
import com.mysql.jdbc.Driver
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
public class jdbc01 {
public static void main(String[] args) throws Exception {
//1.使用反射加载Driver类
// 在加载Driver类时,Driver的静态代码也加载了
// 静态代码完成了注册工作,则完成注册
Class.forName("com.mysql.jdbc.Driver");
String url = "root";
String user = "zzz";
String password = "jdbc:mysel://localhost:3306/zzz_db01";
Connection connection = DriverManager.getConnection(url,user,password);
Scanner scanner = new Scanner(System.in);
//获取输入的值
String userId = scanner.nextLine();
String pwd = scanner.nextLine();
//组织sql语句,语句的 ? 相当于占位符
String sql1 = "insert into actor values(?, ?)";
String sql2 = "update actor set name = ? where age = ?";
String sql3 = "delete from actor where name = ? or age = ?";
//PreparedStatement对象实现了PreparedStatement接口的实现类的对象
PreparedStatement preparedStatement = connection.getPreparedStatement(sql);
//给 ? 占位符赋值
preparedStatement.setString(1,userId);
preparedStatement.setString(2,pwd);
//因为上方已经预处理了sql语句,且赋值了,所以此处执行sql的方法就不需要传参了
preparedStatement.executeUpdate();
}
}
ResultSet
ResultSet对象保持一个光标指向其当前的数据行;
最初,光标位于第一行之前(标题行)。
- next()方法:将光标移动到下一行
- 当ResultSet对象中没有更多行时,返回false,因此可以使用while 循环遍历结果集
- previous()方法:光标向上移动一行
- getXxx(列的索引或者列名)方法:获取该行的某一列
...
ResultSet rs = statement.executeQuery(sql);
while(rs.next()){
int id = rs.getInt(1);//获取该行的第 1 列的数据
String name = rs.getString(2);//获取该行的第 2 列的数据
int age = rs.getInt(3);//获取该行的第 3 列的数据
Date date = rs.getDate(4);//获取该行的第 4 列的数据
System.out.println(id +"\t" + name +"\t" + age +"\t" + date);
}
Utils
在实际开发过程中,获取连接和释放资源是经常用到的,可以将其封装JDBC连接的工具类JDBCUtils
事务
批处理
当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理;
JDBC 批量处理语句
addBatch() :添加需要批量处理的SQL语句或者参数
executeBatch() :执行批量处理语句
clearBatch() :清空批处理包的语句
JDBC批处理在链接MySQL时,需要添加参数
如果要使用批量处理功能,请在URL中添加参数 : ?rewriteBatchedStatements=true
批处理搭配Preparedstatement使用
减少编译次数,减少运行次数,提高效率
传统:sql语句一条一条发送给MySQL执行
...
//组织sql语句,语句的 ? 相当于占位符
String sql1 = "insert into actor values(?, ?)";
//PreparedStatement对象实现了PreparedStatement接口的实现类的对象
PreparedStatement preparedStatement = connection.getPreparedStatement(sql);
for (int i = 0; i < 5000; i++) {
preparedStatement.setString(1,"jack"+i);
preparedStatement.setString(2,"666");
preparedStatement.executeUpdate();
}
批处理:sql语句打包一起发送给MySQL执行
public void batch(){
...
//组织sql语句,语句的 ? 相当于占位符
String sql1 = "insert into actor values(?, ?)";
//PreparedStatement对象实现了PreparedStatement接口的实现类的对象
PreparedStatement preparedStatement = connection.getPreparedStatement(sql);
for (int i = 0; i < 5000; i++) {
preparedStatement.setString(1,"jack"+i);
preparedStatement.setString(2,"666");
//将sql语句加入到批处理包中
preparedStatement.addBatch();
//当有1000条记录时,再批量执行
if ((i+1)%1000 == 0){
preparedStatement.executeBatch();
//清空一把
preparedStatement.clearBatch();
}
}
连接池
传统连接带来的问题
传统连接步骤:
- 得到连接
- 发送sql到mysql
- 关闭连接
- 传统的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection加载到内存中,再验证IP地址,用户名和密码(耗时0.05-1s之间)
- 频繁的进行数据库连接操作将占用很多的系统资源,容易造成数据库崩溃
- 每次连接使用完都要断开,如果程序异常未能关闭,将导致数据库内存泄漏,最终导致重启数据库
- 传统连接的方式不能控制连接数量,如果连接过多,也可能导致内存泄漏,MySQL崩溃
数据库连接池介绍
- 使用连接:预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从缓冲池中取到一个,使用完毕后放回去(引用断开,连接对象还在)
- 重复使用:数据库连接池负责分配,管理和释放数据连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新创建一个
- 请求超出当前连接:当应用程序向连接池请求的连接数量大于连接数量时,这些请求将被加入到等待队列中
连接池的种类
JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现(提供相应的.jar包)
DataSource
DBCP
速度相对C3P0较快,但不稳定
C3P0(旧系统会用到)
老牌的数据库连接池技术,速度相对较慢,稳定性好
连接方式1 :
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P001 {
public void testC3P0_01() throws SQLException {
//创建数据源对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//通过配置文件获取相关信息:musql.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实现
//关闭连接
connection.close();
}
//使用配置文件模板来完成
//将C3P0提供的c3p0-config.xml拷贝到src目录下
//该文件指定了连接数据库和连接池的相关参数
public void testC3P0_02() throws SQLException {
}
}
连接方式2:使用c3p0-config.xml文件连接
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="zzz_dbs">
<!-- 配置数据库用户名 -->
<property name="user">root</property>
<!-- 配置数据库密码 -->
<property name="password"></property>
<!-- 配置数据库链接地址 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/zzz_db01?useUnicode=true&characterEncoding=UTF-8</property>
<!-- 配置数据库驱动 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 数据库连接池一次性向数据库要多少个连接对象 -->
<property name="acquireIncrement">20</property>
<!-- 初始化连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">30</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0 -->
<property name="maxStatements">0</property>
<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection">0</property>
<!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 通过多线程实现多个操作同时被执行。Default:3 -->
<property name="numHelperThreads">3</property>
<!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">3</property>
<!-- 获取连接超时设置 默认是一直等待单位毫秒 -->
<property name="checkoutTimeout">1000</property>
<!--每多少秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">3</property>
<!--最大空闲时间,多少秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">10</property>
<!--配置连接的生存时间,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。 -->
<property name="maxIdleTimeExcessConnections">5</property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null -->
<property name="automaticTestTable">Test</property>
<!-- 获取connnection时测试是否有效 -->
<property name="testConnectionOnCheckin">true</property>
</named-config>
</c3p0-config>
代码
public void testC3P0_02() throws SQLException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("zzz_dbs");
Connection connection = comboPooledDataSource.getConnection();
connection.close();
}
Proxool
有监控连接池状态的功能,稳定性相对C3P0差一点
BoneCP
速度快
Druid(较新技术,新开发使用最多)
阿里提供的数据库连接池,集DBCP,C3P0,Proxool于一身的数据库连接池
准备工作:
- 项目里新建一个只保存第三方包的目录,命名自定义
- 将druid.jar包拷贝到该目录,并将.jar文件加入到项目
- 右键文件 - Add as Library - OK
- 加入druid.properties配置文件,拷贝到项目的src目录
配置文件:
driverClassName=com.mysql.jdbc.Driver //驱动加载
url=jdbc:mysql://127.0.0.1:3306/zzz_db01?characterEncoding=utf-8 //注册驱动
username=root //连接数据库的用户名
password=root //连接数据库的密码。
filters=stat //属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wall
initialSize=2 //初始化时池中建立的物理连接个数。
maxActive=50 //最大的可活跃的连接池数量
maxWait=5000 //获取连接时最大等待时间,单位毫秒,超过连接就会失效。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
timeBetweenEvictionRunsMillis=60000 // 连接回收器的运行周期时间,时间到了清理池中空闲的连接,testWhileIdle根据这个判断
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 1 //用来检测连接是否有效的sql,要求是一个查询语句。
testWhileIdle=true //建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。
testOnBorrow=false //申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。设置为false
testOnReturn=false //归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能,设置为flase
poolPreparedStatements=false //是否缓存preparedStatement,也就是PSCache。
maxPoolPreparedStatementPerConnectionSize=200 // 池中能够缓冲的preparedStatements语句数量
连接数据库连接池
public void testDruid() throws Exception {
//创建Properties对象,读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));
//创建一个指定参数的数据库连接池,druid连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
Connection connection = dataSource.getConnection();
System.out.println("连接成功");
connection.close();
}
基于德鲁伊数据库连接池的工具类
package JDBC_study;
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;
public class JDBCUtilsByDruid {
private static DataSource dataSource ;
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//编写getConnection方法
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//关闭连接,在数据库连接池技术中,close()方法不是duan断掉连接
// 而是把使用的Connection对象放回连接池
public static void close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet != null){
resultSet.close();
}else if (statement != null){
statement.close();
} else if (connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Apache - DBUtils
保存数据时候会遇到的问题
分析:
- 关闭Connection后,ResuleSet结果集无法使用
- ResultSet不利于数据的管理
- ResultSet使用返回信息也不方便
解决方法:
JavaBean(PoJO,Domain)
- 定义一个类A,类的成员属性名跟表的字段名一致,映射一张表
- 返回的一行结果集记录,保存到A实例对象里,再用ArrayList保存A对象,实现保存表数据
引出Apache - DBUtils
基本介绍:
commons-dbutils 是Apache组织提供的一个开源的JDBC工具类库,他是对JDBC的封装,使用dbutils能极大简化JDBC编码的工作量
DbUtils类:
- QueryRunner类,该类封装了SQL 的执行,是线程安全,可以实现增删查改,批处理
- 使用QueryRunner类实现查询
- ResultSetHandler接口,该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式
前置准备
- 项目里新建一个只保存第三方包的目录,命名自定义
- 将commons-dbutils.jar包拷贝到该目录,并将.jar文件加入到项目
- 右键文件 - Add as Library - OK
- 加入druid.properties配置文件,拷贝到项目的src目录
使用Apache-DBUtils 工具类 + druid 完成对表的crud操作
package JDBC_study;
import java.sql.Connection;
public class DBUtils_USE {
//使用Apache-DBUtils 工具类 + druid 完成对表的crud操作
public void testQueryMany(){//返回多行数据
//得到连接
Connection connection = JDBCUtilsByDruid.getConnection();
//使用DBUtils类和接口,先引入DBUtils相关的jar,加入到本Project
//创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql = "select * from actor where id = ? or sex = ? or name = ?";
/*
1. query()就是执行一个sql 语句,并返回resultset ,封装到 ArrayList集合中
2. 返回集合
传入参数解读:
(1) connection :连接
(2) sql : sql语句
(3) new BeanListHandler<>(Actor.class) : 在将resultset 取出到 Actor对象,封装到 ArrayList 中
底层使用了反射机制,查看获取Actor类 的属性,然后进行封装
(4) 1,2,3 :就是sql中的?,是可变参数
*/
List<Actor> list = queryRunner.query(connection,sql,new BeanListHandler<>(Actor.class),1,2,3);
//(5) 底层得到的resultset,会在query关闭,还会关闭PreparedStatment
JDBCUtilsByDruid.close(null,null,connection);
}
public void testQuerySingle(){//返回单行数据 BeanHandler
//得到连接
Connection connection = JDBCUtilsByDruid.getConnection();
//使用DBUtils类和接口,先引入DBUtils相关的jar,加入到本Project
//创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql = "select * from actor where id = ?";
Actor actor = queryRunner.query(connection,sql,new BeanHandler<>(Actor.class),1);
JDBCUtilsByDruid.close(null,null,connection);
}
public void testQueryScalar(){//返回单行单列数据 ScalarHandler
//得到连接
Connection connection = JDBCUtilsByDruid.getConnection();
//使用DBUtils类和接口,先引入DBUtils相关的jar,加入到本Project
//创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql = "select name from actor where id = ?";
Object o = queryRunner.query(connection,sql,new ScalarHandler<>(Actor.class),1);
JDBCUtilsByDruid.close(null,null,connection);
}
public void testDML(){//返回单行单列数据 ScalarHandler
//得到连接
Connection connection = JDBCUtilsByDruid.getConnection();
//使用DBUtils类和接口,先引入DBUtils相关的jar,加入到本Project
//创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql1 = "update actor set name = ? where id = ?";
String sql2 = "delete from actor where id = ?";
String sql3 = "insert into actor values(null,?,?,?)";
//返回值是受影响的行数
int affectdRow = queryRunner.update(connection,sql,1);
System.out.println(affectdRow > 0? "成功":"没有影响到表");
JDBCUtilsByDruid.close(null,null,connection);
}
}
DAO增删改查 - BasicDao
Apache - DBUtils会遇到的问题
问题分析:
- Apache - DBUtils简化了JDBC的开发,但还有不足
- SQL语句是固定的,不能通过参数传入,通用性不好,需要进行改进,更方便地执行curd
- 对于select来说,如果有返回值,返回类型不能固定,需要使用泛型
- 将来的表很多,业务需求复杂,不可能只靠一个Java完成
引出DAO(Data access object)数据访问对象
- BasicDAO :通用类,是专门和数据库交互的,即完成对数据库的curd操作
- 在BasicDAO的基础上,实现一张表对应一个DAO,更好地完成功能
- Actor表 -- Actor.java类 -- ActorDAO.java
- 包com.zzz.dao_
- dao 存放XxxDAO和BasicDAO
- BasicDAO
- domain javabean
- utils 工具类
JDBCUtilsByDruid
- test 写测试类
BasicDAO
package com.zzz.dao_.dao;
import com.zzz.dao_.utils.JDBCUtilsByDruid;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class BasicDAO<T> {
private QueryRunner qr = new QueryRunner();
public int updateDAO(String sql, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
int update = qr.update(connection,sql,parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtilsByDruid.close(null, null,connection);
}
}
//查询结果多行,针对任意表
/**
*
* @param sql sql语句
* @param cls 传入一个类的Class对象,反射会使用到,如Actor.class
* @param parameters 传入问号具体值
* @return
*/
public List<T> queryMulti(String sql, Class<T> cls, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection,sql,new BeanListHandle<>(cls),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtilsByDruid.close(null, null,connection);
}
}
public List<T> querySingle(String sql, Class<T> cls, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection,sql,new BeanHandle<>(cls),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtilsByDruid.close(null, null,connection);
}
}
public List<T> queryScalar(String sql, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return qr.query(connection,sql,new ScalarHandle(),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtilsByDruid.close(null, null,connection);
}
}
}
JDBCUtilsByDruid
package com.zzz.dao_.utils;
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;
public class JDBCUtilsByDruid {
private static DataSource dataSource ;
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//编写getConnection方法
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//关闭连接,在数据库连接池技术中,close()方法不是duan断掉连接
// 而是把使用的Connection对象放回连接池
public static void close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet != null){
resultSet.close();
}else if (statement != null){
statement.close();
} else if (connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}