一、JDBC快速入门
1.概念
- JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系型数据库提供统一访问,它是由一组用Java语言编写的类和接口组成的。
2.本质
- 其实就是java官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接!
4.快速入门
1)导入jia包
2)注册驱动
// MySQL 5
Class.forName("com.mysql.jdbc.Driver");
// MySQL 8
Class.forName("com.mysql.cj.jdbc.Driver");
3)获取连接
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "root");
4)获取执行者对象
Statement stat = con.createStatement();
5)执行sql语言,并接受返回结果
String sql = "SELECT * FROM user";
ResultSet rs = stat.executeQuery(sql);
6)处理结果
while(rs.next()) {
System.out.println(rs.getInt("id") + "\t" + rs.getString("name"));
}
7)释放资源
con.close();
stat.close();
rs.close();
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db", "root", "");
Statement statement = connection.createStatement();
String sql = "Select * from account";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println(
"id:"+resultSet.getInt("id") + "\t"
+"name:"+resultSet.getString("name") + "\t"
+"money:"+resultSet.getDouble("money")
);
}
connection.close();
statement.close();
resultSet.close();
}
}
二、API介绍
1.DriverManager
-
DriverManager:驱动管理对象
-
注册驱动(告诉程序该使用哪一个数据库驱动)
- static void registerDriver(Driver driver):注册与给定的驱动程序 DriverManager
- 写代码使用:Class.forName("com.mysql.jdbc.Driver");
- 通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块
static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
- 注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。在jar包中,存在一个java.sql.Driver配置文件,文件中指定了com.mysql.jdbc.Driver
-
获取数据库连接(获取到数据库的连接并返回连接对象)
- static Connection getConnection(String url, String user, String password);
- 返回值:Connection数据库连接对象
- 参数
- url:指定连接的路径。语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
- user:用户名
- password:密码
- static Connection getConnection(String url, String user, String password);
-
2.Connection
- Connection:数据库连接对象
- 获取执行者对象
- 获取普通执行者对象:Statement createStatement();
- 获取预编译执行者对象:PreparedStatement prepareStatement(String sql);
- 管理事务
- 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
- 提交事务:commit();
- 回滚事务:rollback();
- 释放资源
- 立即将数据库连接对象释放:void close();
- 获取执行者对象
3.Statement
- Statement:执行sql语句的对象
- 执行DML语句:int executeUpdate(String sql);
- 返回值int:返回影响的行数。
- 参数sql:可以执行insert、update、delete语句。
- 执行DQL语句:ResultSet executeQuery(String sql);
- 返回值ResultSet:封装查询的结果。
- 参数sql:可以执行select语句。
- 释放资源
- 立即将执行者对象释放:void close();
- 执行DML语句:int executeUpdate(String sql);
4.ResultSet
- ResultSet:结果集对象
- 判断结果集中是否还有数据:boolean next();
- 有数据返回true,并将索引向下移动一行
- 没有数据返回false
- 获取结果集中的数据:XXX getXxx("列名");
- XXX代表数据类型(要获取某列数据,这一列的数据类型)
- 例如:String getString("name"); int getInt("age");
- 释放资源
- 立即将结果集对象释放:void close();
- 判断结果集中是否还有数据:boolean next();
三、使用
1.数据准备
1)数据库
-- 创建student表
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT, -- 学生id
NAME VARCHAR(20), -- 学生姓名
age INT, -- 学生年龄
birthday DATE -- 学生生日
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'1999-09-23'),(NULL,'李四',24,'1998-08-10'),(NULL,'王五',25,'1996-06-06'),(NULL,'赵六',26,'1994-10-20');
2)实体类
package com.itheima02.domain;
import java.util.Date;
public class Student {
private Integer sid;
private String name;
private Integer age;
private Date birthday;
public Student() {
}
public Student(Integer sid, String name, Integer age, Date birthday) {
this.sid = sid;
this.name = name;
this.age = age;
this.birthday = birthday;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
}
2.查询全部
1)持久层
public class StudentDaoImpl implements StudentDao {
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 注册驱动 可省
//Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db","root","");
// 获取执行者对象
statement = connection.createStatement();
// 执行sql语句 接受返回的结果集
String sql = "select * from student";
resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("sid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
Student student = new Student(id, name, age, birthday);
list.add(student);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 释放资源
try {
if (connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return list;
}
}
2)服务层
public class StudentServiceImpl implements StudentService {
private StudentDao studentDao = new StudentDaoImpl();
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> all = studentDao.findAll();
return all;
}
}
3)视图层
public class StudentController {
private StudentService studentService = new StudentServiceImpl();
@Test
public void findAll(){
ArrayList<Student> all = studentService.findAll();
for (Student student : all) {
System.out.println(student);
}
}
}
3. 条件查询
@Override
public Student findById(Integer sid) {
Student student = null;
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 注册驱动 可省
//Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db","root","");
// 获取执行者对象
statement = connection.createStatement();
// 执行sql语句 接受返回的结果集
String sql = "select * from student where sid ="+sid;
resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("sid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
student = new Student(id, name, age, birthday);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 释放资源
try {
if (connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return student;
}
@Override
public Student findById(Integer sid) {
Student student = studentDao.findById(sid);
return student;
}
@Test
public void findById(){
Student student = studentService.findById(1);
System.out.println(student);
}
4.添加信息
int result = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String sql = "insert into student values ("
+ student.getSid()+",'"
+ student.getNAME()+"',"
+ student.getAge()+",'"
+ sdf.format(student.getBirthday())
+"')";
result = statement.executeUpdate(sql);
tips: 字符串和时间要用小括号包起来
5.修改信息
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String sql = "update student set name = "+
"'"+student.getName()+ "',age=" +
student.getAge()+ ",birthday='"
+sdf.format(student.getBirthday())+
"' where sid ="+student.getSid();
resultSet = statement.executeUpdate(sql);
5.删除信息
String sql = "delete from student where sid = 6";
resultSet = statement.executeUpdate(sql);
四、工具类
1.配置文件
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db14
username=root
password=itheima
2.工具类
package com.codeui.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
// 私有化构造方法
private JDBCUtils(){};
// 声明配置信息
private static String driverClass;
private static String url;
private static String username;
private static String password;
private static Connection connection;
// 静态代码块实现加载配置文件和注册驱动
static {
try {
// 通过类加载器返回配置文件的字节流
InputStream resourceAsStream = JDBCUtils.class.getClassLoader().getResourceAsStream(
"config.properties");
//创建properties集合,加载流对象的信息
Properties properties = new Properties();
properties.load(resourceAsStream);
//获取信息为变量赋值
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driverClass);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接数据库的方法
public static Connection getConnection(){
try {
connection = DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//释放资源
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Connection connection,Statement statement){
close(connection,statement,null);
}
}
3.使用
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 获取连接
connection = JDBCUtils.getConnection();
// 获取执行者对象
statement = connection.createStatement();
// 执行sql语句 接受返回的结果集
String sql = "select * from student";
resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("sid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
Student student = new Student(id, name, age, birthday);
list.add(student);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(connection,statement,resultSet);
}
return list;
}
五、SQL注入攻击
1.演示
我们会发现即使密码错误,我们也可以登录,原因是Statement对象在执行sql语句时,将一部分内容当做查询条件来执行了。
2.PreparedStatement的介绍
- 预编译sql语句的执行者对象。在执行sql语句之前,将sql语句进行提前编译。
- 原本 sql语句 password = aaa or 1=1;
- 现在 sql语句 password = "aaa or 1=1"
- 会发现"aaa or 1=1"变成了参数而不是语句加参数
- 为参数赋值的方法:setXxx(参数1,参数2);
- 参数1:?的位置编号(编号从1开始)
- 参数2:?的实际参数
- 执行sql语句的方法
- 执行insert、update、delete语句:int executeUpdate();
- 执行select语句:ResultSet executeQuery();
String sql = "SELECT * FROM user WHERE loginname=? AND password=?";
pstm = conn.prepareStatement(sql);
//设置参数
pstm.setString(1,loginName);
pstm.setString(2,password);
//执行sql语句,获取结果集
rs = pstm.executeQuery();
六、事务管理
事务管理一般在服务层实现
- 管理事务的功能类 Connection
- 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则开启事务。
- 提交事务:commit();
- 回滚事务:rollback();
七、数据库连接池
1.数据库连接池的概念
- 数据库连接背景
- 数据库连接是一种关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
- 数据库连接池
- 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能。
2.自定义连接池
- DataSource
- 数据源(数据库连接池),java官方提供的数据库连接池规范接口
- 核心功能 Connection getConnection();
// 准备容器,用于保存多个连接对象
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());
// 定义静态代码块,通过工具类获得10个连接对象
static {
for (int i=0; i<10; i++){
Connection connection = JDBCUtils.getConnection();
pool.add(connection);
}
}
// 重写getConnection(),用于获得;一个连接对象
@Override
public Connection getConnection() throws SQLException {
if (pool.size()>0){
Connection remove = pool.remove(0);
return remove;
} else {
throw new RuntimeException("连接数量已用尽");
}
}
public int getSize(){
return pool.size();
}
1)1.测试
public class MyDataSourceTest {
public static void main(String[] args) throws SQLException {
// 创建连接池对象
MyDataSource dataSource = new MyDataSource();
System.out.println("前:"+dataSource.getSize());
// 通过连接池对象获取连接对象
Connection connection = dataSource.getConnection();
// 查询学生的全部信息
String sql = "select * from student";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getInt("sid"));
}
JDBCUtils.close(connection,preparedStatement,resultSet);
System.out.println("后:"+dataSource.getSize());
}
}
3.归还连接
- 归还方法
- 继承方式
- 装饰设计模式
- 适配器设计模式
- 动态代理模式
1)继承方式(mysql 5)
-
定义一个类继承JDBC4Connection
-
定义Connection连接对象和连接容器对象的成员变量
-
通过有参构造方法完成对变量赋值
-
重写close方法,将对象添加到池中
/*
自定义Connection类
*/
public class MyConnection1 extends JDBC4Connection {
//声明连接对象和连接池集合对象
private Connection con;
private List<Connection> pool;
//通过构造方法给成员变量赋值
public MyConnection1(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url,Connection con,List<Connection> pool) throws SQLException {
super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
this.con = con;
this.pool = pool;
}
//重写close()方法,将连接归还给池中
@Override
public void close() throws SQLException {
pool.add(con);
}
}
//将之前的连接对象换成自定义的子类对象
private static MyConnection1 con;
//4.获取数据库连接的方法
public static Connection getConnection() {
try {
//等效于:MyConnection1 con = new JDBC4Connection(); 语法错误!
con = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
我们虽然自定义了一个子类,完成了归还连接的操作。但是DriverManager获取的还是JDBC4Connection这个对象,并不是我们的子类对象。而我们又不能整体去修改驱动包中类的功能!
2)装饰设计模式
-
思想
- 定义一个类,实现Connection接口,这样就具备了和JDBC4Connection相同的方法
- 重写close方法,完成归还连接操作,其余功能还是用Mysql驱动包原有方法
-
步骤
-
定义一个类实现Connection接口
-
定义Connection连接对象和连接容器对象的成员变量
-
通过有参构造方法完成对变量赋值
-
重写close方法,将对象添加到池中
-
剩余方法,只需要调用mysql驱动包的的连接对象完成即可
-
在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装
package com.codeui.data; import com.codeui.utils.JDBCUtils; import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Logger; public class MyDataSource implements DataSource { // 准备容器,用于保存多个连接对象 private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>()); // 定义静态代码块,通过工具类获得10个连接对象 static { for (int i=0; i<10; i++){ Connection connection = JDBCUtils.getConnection(); System.out.println("池"+connection); pool.add(connection); } } // 重写getConnection(),用于获得;一个连接对象 @Override public Connection getConnection() throws SQLException { if (pool.size()>0){ Connection connection = pool.remove(0); MyConnection myConnection = new MyConnection(connection,pool); return myConnection; } else { throw new RuntimeException("连接数量已用尽"); } } public int getSize(){ return pool.size(); } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } }
MyConnection
package com.codeui.data; import com.mysql.cj.jdbc.ConnectionImpl; import java.sql.*; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; /** * 定义一个类继承JDBC4Connection * 定义Connection连接对象和连接容器对象的成员变量 * 通过有参构造方法完成对变量赋值 * 重写close方法,将对象添加到池中 * */ public class MyConnection implements Connection { private Connection con; private List<Connection> pool; public MyConnection(Connection con, List<Connection> pool){ this.con = con; this.pool = pool; } @Override public void close() throws SQLException { pool.add(con); } @Override public Statement createStatement() throws SQLException { return con.createStatement(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return con.prepareStatement(sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { return con.prepareCall(sql); } @Override public String nativeSQL(String sql) throws SQLException { return con.nativeSQL(sql); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { con.setAutoCommit(autoCommit); } @Override public boolean getAutoCommit() throws SQLException { return con.getAutoCommit(); } @Override public void commit() throws SQLException { con.commit(); } @Override public void rollback() throws SQLException { con.rollback(); } @Override public boolean isClosed() throws SQLException { return con.isClosed(); } @Override public DatabaseMetaData getMetaData() throws SQLException { return con.getMetaData(); } @Override public void setReadOnly(boolean readOnly) throws SQLException { con.setReadOnly(readOnly); } @Override public boolean isReadOnly() throws SQLException { return con.isReadOnly(); } @Override public void setCatalog(String catalog) throws SQLException { con.setCatalog(catalog); } @Override public String getCatalog() throws SQLException { return con.getCatalog(); } @Override public void setTransactionIsolation(int level) throws SQLException { con.setTransactionIsolation(level); } @Override public int getTransactionIsolation() throws SQLException { return con.getTransactionIsolation(); } @Override public SQLWarning getWarnings() throws SQLException { return con.getWarnings(); } @Override public void clearWarnings() throws SQLException { con.clearWarnings(); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return con.createStatement(resultSetType,resultSetConcurrency); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return con.prepareStatement(sql,resultSetType,resultSetConcurrency); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { return con.prepareCall(sql,resultSetType,resultSetConcurrency); } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { return con.getTypeMap(); } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { con.setTypeMap(map); } @Override public void setHoldability(int holdability) throws SQLException { con.setHoldability(holdability); } @Override public int getHoldability() throws SQLException { return con.getHoldability(); } @Override public Savepoint setSavepoint() throws SQLException { return con.setSavepoint(); } @Override public Savepoint setSavepoint(String name) throws SQLException { return con.setSavepoint(name); } @Override public void rollback(Savepoint savepoint) throws SQLException { con.rollback(savepoint); } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { con.releaseSavepoint(savepoint); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return con.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { return con.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { return con.prepareStatement(sql,autoGeneratedKeys); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { return con.prepareStatement(sql,columnIndexes); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { return con.prepareStatement(sql,columnNames); } @Override public Clob createClob() throws SQLException { return con.createClob(); } @Override public Blob createBlob() throws SQLException { return con.createBlob(); } @Override public NClob createNClob() throws SQLException { return con.createNClob(); } @Override public SQLXML createSQLXML() throws SQLException { return con.createSQLXML(); } @Override public boolean isValid(int timeout) throws SQLException { return con.isValid(timeout); } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { con.setClientInfo(name,value); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { con.setClientInfo(properties); } @Override public String getClientInfo(String name) throws SQLException { return con.getClientInfo(name); } @Override public Properties getClientInfo() throws SQLException { return con.getClientInfo(); } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { return con.createArrayOf(typeName,elements); } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { return con.createStruct(typeName,attributes); } @Override public void setSchema(String schema) throws SQLException { con.setSchema(schema); } @Override public String getSchema() throws SQLException { return con.getSchema(); } @Override public void abort(Executor executor) throws SQLException { con.abort(executor); } @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { con.setNetworkTimeout(executor,milliseconds); } @Override public int getNetworkTimeout() throws SQLException { return con.getNetworkTimeout(); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return con.unwrap(iface); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return con.isWrapperFor(iface); } }
-
3)适配器设计模式
- 提供一个适配器类,实现Connection接口,将所有功能进行实现(除了close方法)。自定义连接类只需要继承这个适配器类,重写需要改进的close()方法即可!
- 步骤
- 定义一个适配器类实现Connection接口
- 定义Connection连接对象的成员变量
- 通过有参构造方法完成对成员变量的赋值
- 重写所有方法(除了close()),调用mysql驱动包的连接对象完成即可
- 定义一个连接类,继承适配器类
- 定义Connection连接对象和连接池容器的成员变量,并通过有参构造方法进行赋值
- 重写close()方法,完成归还链接
- 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装。
/*
适配器抽象类。实现Connection接口。
实现所有的方法,调用mysql驱动包中Connection连接对象的方法
*/
public abstract class MyAdapter implements Connection {
// 定义数据库连接对象的变量
private Connection con;
// 通过构造方法赋值
public MyAdapter(Connection con) {
this.con = con;
}
// 所有的方法,均调用mysql的连接对象实现
@Override
public Statement createStatement() throws SQLException {
return con.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return con.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return con.prepareCall(sql);
}
@Override
public String nativeSQL(String sql) throws SQLException {
return con.nativeSQL(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
con.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
return con.getAutoCommit();
}
@Override
public void commit() throws SQLException {
con.commit();
}
@Override
public void rollback() throws SQLException {
con.rollback();
}
@Override
public boolean isClosed() throws SQLException {
return con.isClosed();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return con.getMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
con.setReadOnly(readOnly);
}
@Override
public boolean isReadOnly() throws SQLException {
return con.isReadOnly();
}
@Override
public void setCatalog(String catalog) throws SQLException {
con.setCatalog(catalog);
}
@Override
public String getCatalog() throws SQLException {
return con.getCatalog();
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
con.setTransactionIsolation(level);
}
@Override
public int getTransactionIsolation() throws SQLException {
return con.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return con.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
con.clearWarnings();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return con.createStatement(resultSetType,resultSetConcurrency);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return con.prepareStatement(sql,resultSetType,resultSetConcurrency);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return con.prepareCall(sql,resultSetType,resultSetConcurrency);
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return con.getTypeMap();
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
con.setTypeMap(map);
}
@Override
public void setHoldability(int holdability) throws SQLException {
con.setHoldability(holdability);
}
@Override
public int getHoldability() throws SQLException {
return con.getHoldability();
}
@Override
public Savepoint setSavepoint() throws SQLException {
return con.setSavepoint();
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return con.setSavepoint(name);
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
con.rollback(savepoint);
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
con.releaseSavepoint(savepoint);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return con.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return con.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return con.prepareStatement(sql,autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return con.prepareStatement(sql,columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return con.prepareStatement(sql,columnNames);
}
@Override
public Clob createClob() throws SQLException {
return con.createClob();
}
@Override
public Blob createBlob() throws SQLException {
return con.createBlob();
}
@Override
public NClob createNClob() throws SQLException {
return con.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
return con.createSQLXML();
}
@Override
public boolean isValid(int timeout) throws SQLException {
return con.isValid(timeout);
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
con.setClientInfo(name,value);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
con.setClientInfo(properties);
}
@Override
public String getClientInfo(String name) throws SQLException {
return con.getClientInfo(name);
}
@Override
public Properties getClientInfo() throws SQLException {
return con.getClientInfo();
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return con.createArrayOf(typeName,elements);
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return con.createStruct(typeName,attributes);
}
@Override
public void setSchema(String schema) throws SQLException {
con.setSchema(schema);
}
@Override
public String getSchema() throws SQLException {
return con.getSchema();
}
@Override
public void abort(Executor executor) throws SQLException {
con.abort(executor);
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
con.setNetworkTimeout(executor,milliseconds);
}
@Override
public int getNetworkTimeout() throws SQLException {
return con.getNetworkTimeout();
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return con.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return con.isWrapperFor(iface);
}
}
public class MyConnection extends MyAdapter {
private Connection con;
private List<Connection> pool;
public MyConnection(Connection connection,List<Connection> pool){
super(connection);
this.con = connection;
this.pool = pool;
}
@Override
public void close() throws SQLException {
pool.add(con);
}
}
4)动态代理
1.快速入门
在不改变目标对象方法的情况下对方法进行增强
-
组成
- 被代理对象:真实的对象
- 代理对象:内存中的一个对象
-
要求
- 代理对象和被代理对象要实现相同的接口
-
实现
- newProxyInstance(ClassLoader loader,interfaces,InvocationHandler h)
-
参数
- ClassLoader loader 和被代理对象使用相同的类加载器
- Class<?>[] interfaces 接口类型Class数组,和被代理对象使用相同接口
- InvocationHandler h 代理规则 完成代理增强的功能
public interface StudentInterface {
void eat(String name);
void study();
}
public class Student implements StudentInterface{
@Override
public void eat(String name) {
System.out.println(name+"在家吃");
}
@Override
public void study() {
System.out.println("在家学");
}
}
public class Test {
public static void main(String[] args) {
Student student = new Student();
StudentInterface proxyInstance = (StudentInterface) Proxy.newProxyInstance(student.getClass().getClassLoader(), new Class[]{StudentInterface.class}, new InvocationHandler() {
/*
* 执行Student类中所有方法都会经过invoke方法
* 对method方法进行判断
* 如果是study方法,则对其增强
* 如果不是,就调用原方法即可
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("study")) {
System.out.println("来codeui学习");
return null;
} else {
return method.invoke(student, args);
}
}
});
proxyInstance.study();
}
}
2.动态代理方式归还连接池
- 步骤
- 定义一个类实现DataSource接口
- 定义一个容器,用于保存多个Connection连接对象
- 定义静态代码块,通过jdbc工具类获取101个对象保存到容器中
- 重写getConnection方法,从容器中获取一个连接
- 通过Poxy代理,如果是close()方法,就将连接归还池中,如果是其他方法则调用原有功能
- 定义getSise方法,用于获取容器的大小并返回
@Override
public Connection getConnection() throws SQLException {
if (pool.size()>0){
Connection connection = pool.remove(0);
Connection con = (Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
/*
执行Connection实现类对象所有方法都会经过invoke
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("close")){
pool.add(connection);
return null;
}else {
return method.invoke(connection,args);
}
}
});
return con;
} else {
throw new RuntimeException("连接数量已用尽");
}
}
4.了解C3P0连接池
-
需要导入jar包
- c3p0-0.9.5.2.jar
- mchange-commons-java-0.2.12.jar
-
c3p0的配置文件会自动加载,但是必须c3p0-config.xml或c3p0-config.properties
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db</property>
<property name="user">root</property>
<property name="password">itheima</property>
<!-- 连接池参数 -->
<!-- 初始化连接数量-->
<property name="initialPoolSize">5</property>
<!-- 最大连接数量-->
<property name="maxPoolSize">10</property>
<!-- 超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 可以选择默认配置,也可以自己设置-->
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test_db</property>
<property name="user">root</property>
<property name="password"></property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
public class C3P0Test {
public static void main(String[] args) throws SQLException {
// 创建c3p0连接池对象
DataSource dataSource = new ComboPooledDataSource();
// 通过连接池对象获取连接
Connection connection = dataSource.getConnection();
// 获取执行者对象
Statement statement = connection.createStatement();
// 执行sql语句 接受返回的结果集
String sql = "select * from student";
ResultSet resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("sid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
Student student = new Student(id, name, age, birthday);
System.out.println(student);
}
//
}
}
5.了解Druid连接池
- 导入jar包
- 编写配置文件,src目录下
- 通过Properties集合加载配置文件
- 通过Druid连接池工厂类获取数据库连接池对象
- 通过连接池对象获取连接
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_db
username=root
password=
initialSize=5
maxActive=10
maxWait=3000
public class DruidTest {
public static void main(String[] args) throws Exception {
// 获取配置文件流对象,加载配置文件
InputStream resourceAsStream = DruidTest.class.getClassLoader().getResourceAsStream("druid.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 通过连接池对象获取连接
Connection connection = dataSource.getConnection();
// 获取执行者对象
Statement statement = connection.createStatement();
// 执行sql语句 接受返回的结果集
String sql = "select * from student";
ResultSet resultSet = statement.executeQuery(sql);
// 处理结果集
while (resultSet.next()) {
Integer id = resultSet.getInt("sid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
Date birthday = resultSet.getDate("birthday");
Student student = new Student(id, name, age, birthday);
System.out.println(student);
}
}
}
6.抽取工具类
/*
数据库连接池工具类
*/
public class DataSourceUtils {
//1.私有构造方法
private DataSourceUtils(){}
//2.定义DataSource数据源变量
private static DataSource dataSource;
//3.提供静态代码块,完成配置文件的加载和获取连接池对象
static {
try{
//加载配置文件
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
Properties prop = new Properties();
prop.load(is);
//获取数据库连接池对象
dataSource = DruidDataSourceFactory.createDataSource(prop);
} catch(Exception e) {
e.printStackTrace();
}
}
//4.提供获取数据库连接的方法
public static Connection getConnection() {
Connection con = null;
try {
con = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
//5.提供获取数据库连接池的方法
public static DataSource getDataSource() {
return dataSource;
}
//6.提供释放资源的方法
public static void close(Connection con, Statement stat, ResultSet rs) {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stat != null) {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection con, Statement stat) {
close(con,stat,null);
}
}
八、JDBCTemplate
- 目的
- 抽取出一个JDBC模板类,来封装一些方法(update、query),专门执行增删改查的sql语句,简化使用步骤
1.数据库的源信息
- DataBaseMetaData(了解):数据库的源信息
- java.sql.DataBaseMetaData:封装了整个数据库的综合信息
- 例如:
- String getDatabaseProductName():获取数据库产品的名称
- int getDatabaseProductVersion():获取数据库产品的版本号
- ParameterMetaData:参数的源信息
- java.sql.ParameterMetaData:封装的是预编译执行者对象中每个参数的类型和属性
- 这个对象可以通过预编译执行者对象中的getParameterMetaData()方法来获取
- 核心功能:
- int getParameterCount():获取sql语句中参数的个数
- ResultSetMetaData:结果集的源信息
- java.sql.ResultSetMetaData:封装的是结果集对象中列的类型和属性
- 这个对象可以通过结果集对象中的getMetaData()方法来获取
- 核心功能:
- int getColumnCount():获取列的总数
- String getColumnName(int i):获取列名
2.update()方法
-
定义参数变量(数据源,连接对象,执行者对象,结果集对象)
-
通过有参构造方法给数据源赋值
-
定义updata方法,参数:sql语句,sql参数
-
定义int类型变量,用于接受增删改后影响大的行数
-
通过数据源获取一个数据库连接
-
通过数据库连接对象获取执行者对象,并对sql语句进行预编译
-
通过执行者对象获取参数的源信息对象
-
通过通过参数源信息对象获取参数个数
-
判断参数数量是否一致
-
为占位符赋值
-
执行sql语句并接受结果
-
释放资源
-
返回结果
package com.codeui.jdbc;
import com.codeui.utils.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.*;
public class JDBCTemplate {
//定义参数变量(数据源,连接对象,执行者对象,结果集对象)
private DataSource dataSource;
private Connection connection;
private PreparedStatement preparedStatement;
private ResultSet resultSet;
//通过有参构造方法给数据源赋值
public JDBCTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
//定义updata方法,参数:sql语句,sql参数
public int update(String sql, Object...objects){
//定义int类型变量,用于接受增删改后影响大的行数
int result = 0;
try {
//通过数据源获取一个数据库连接
connection = dataSource.getConnection();
//通过数据库连接对象获取执行者对象,并对sql语句进行预编译
preparedStatement = connection.prepareStatement(sql);
// 通过执行者对象获取参数的源信息对象
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
//通过通过参数源信息对象获取参数个数
int parameterCount = parameterMetaData.getParameterCount();
//判断参数数量是否一致
if(parameterCount != objects.length){
throw new RuntimeException("参数个数不匹配");
}
//为占位符赋值
for (int i=0; i<objects.length; i++){
preparedStatement.setObject(i+1,objects[i]);
}
//执行sql语句并接受结果
result = preparedStatement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放资源
DataSourceUtils.close(connection,preparedStatement);
}
//返回结果
return result;
}
}
private JDBCTemplate jdbcTemplate = new JDBCTemplate(DataSourceUtils.getDataSource());
@Test
public void update(){
String sql = "update student set name = ? where sid = ?";
int update = jdbcTemplate.update(sql,"丽丽",1);
System.out.println(update);
}
3.查询方法
- 查询一条记录并封装对象的方法:querforObject()
- 查询多条记录并封装集合的方法:querForList()
- 查询聚合函数并返回单条数据的方法:queryForScalar()
1)处理结果集的接口
1.定义泛型接口ResultSetHandler< T >
/*
* 用于处理结果集的规范接口
* */
public interface ResultSetHandler<T> {
<T> T handler(ResultSet resultSet);
}
- 定义一个类实现RestltSerHandler接口
- 定义Class对象类型变量
- 通过有参构造为变量赋值
- 重写headler方法,用于将一条记录封装到自定义对象中
- 声明自定义对象类型
- 创建传递参数的对象,为自定义对象赋值
- 判断结果集中是否有数据
- 通过结果集对象获取结果集源信息的对象
- 通过结果集源信息对象获取列数
- 通过循环遍历列数
- 通过结果集信息源获取列名
- 通过列名获取数据
- 创建属性描述器对象,将获取的值通过该对象的set方法进行赋值
- 返回封装好的对象
package com.codeui.jdbc;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.List;
// * 定义一个类实现RestltSerHandler接口
public class BeanHandler<T> implements ResultSetHandler<T>{
// * 定义Class对象类型变量
private Class<T> beanClass;
// * 通过有参构造为变量赋值
public BeanHandler(Class<T> beanClass){
this.beanClass = beanClass;
}
// * 重写headler方法,用于将一条记录封装到自定义对象中
@Override
public <T> T handler(ResultSet resultSet) {
// * 声明自定义对象类型
T bean = null;
try {
// * 创建传递参数的对象,为自定义对象赋值
bean = (T) beanClass.getDeclaredConstructor().newInstance();
// * 判断结果集中是否有数据
if ( resultSet.next()){
// * 通过结果集对象获取结果集源信息的对象
ResultSetMetaData metaData = resultSet.getMetaData();
// * 通过结果集源信息对象获取列数
int columnCount = metaData.getColumnCount();
// * 通过循环遍历列数
for (int i=1; i<=columnCount; i++){
// * 通过结果集信息源获取列名
String columnName = metaData.getColumnName(i);
// * 通过列名获取数据
Object value = resultSet.getObject(columnName);
// * 创建属性描述器对象,将获取的值通过该对象的set方法进行赋值
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName.toLowerCase(),beanClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(bean,value);
}
// * 返回封装好的对象
return bean;
};
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
2.定义用于处理结果集的泛型方法< T >Thandler(ResultSet resultSet)
public interface ResultSetHandler<T> {
<T> T handler(ResultSet resultSet);
}
2)queryForObject() 返回一个对象
-
定义queryForObject方法,参数 sql、 处理结果集接口、sql中的参数
-
声明自定义类型对象
-
通过数据源获取数据库连接对象
-
通过连接对象获取执行者对象并对sql语句进行预编译
-
通过执行者对象获取参数源信息的对象
-
通过参数源信息对象获取参数的个数
-
判断参数数量是否一致
-
为sql语句中?占位符赋值
-
执行sql语句并接收结果集
-
释放资源
-
返回结果
public <T> T queryForObject(String sql,ResultSetHandler resultSetHandler ,Object... objects){ T object = null; try { //通过数据源获取一个数据库连接 connection = dataSource.getConnection(); //通过数据库连接对象获取执行者对象,并对sql语句进行预编译 preparedStatement = connection.prepareStatement(sql); // 通过执行者对象获取参数的源信息对象 ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData(); //通过通过参数源信息对象获取参数个数 int parameterCount = parameterMetaData.getParameterCount(); //判断参数数量是否一致 if(parameterCount != objects.length){ throw new RuntimeException("参数个数不匹配"); } //为占位符赋值 for (int i=0; i<objects.length; i++){ preparedStatement.setObject(i+1,objects[i]); } //执行sql语句并接受结果 resultSet = preparedStatement.executeQuery(); // 通过BeanHandler方法对结果集进行处理 object = (T) resultSetHandler.handler(resultSet); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { //释放资源 DataSourceUtils.close(connection,preparedStatement,resultSet); } //返回结果 return object; }
@Test
public void queryForObject(){
String sql = "select * from student where sid = ?";
Student student = jdbcTemplate.queryForObject(sql, new BeanHandler(Student.class), 1);
System.out.println(student);
}
3)queryForList 返回一个集合
- 定义BeanListHandler< T>类实现 ResultSetHandler< T>接口
- 定义Class对象类型的变量
- 定义有参构造为变量赋值
- 重写handler方法,用于将结果集中的所有记录封装到集合中并返回
- 创建List集合对象
- 遍历结果集对象
- 创建传递参数的对象
- 通过结果集对象获取结果集的源信息对象
- 通过结果集原信息对象获取列数
- 同过循环遍历列数
- 通过结果集源信息获取列名
- 通过列名获取该列的数据
- 创建属性描述器对象,将获取到的值通过对象的set()方法进行赋值
- 将封装好的对象添加到集合中
- 返回集合对象
1.BeanListHandler
package com.codeui.jdbc;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
//定义BeanListHandler< T>类实现 ResultSetHandler< T>接口
public class BeanListHandler<T> implements ResultSetHandler<T> {
//* 定义Class对象类型的变量
private Class<T> beanClass;
//* 定义有参构造为变量赋值
public BeanListHandler(Class<T> beanClass) {
this.beanClass = beanClass;
}
//* 重写handler方法,用于将结果集中的所有记录封装到集合中并返回
@Override
public List<T> handler(ResultSet resultSet) {
//创建List集合对象
List<T> list = new ArrayList<>();
try {
//遍历结果集对象
while (!resultSet.next()) {
//* 创建传递参数的对象
T bean = beanClass.getDeclaredConstructor().newInstance();
//* 通过结果集对象获取结果集的源信息对象
ResultSetMetaData metaData = resultSet.getMetaData();
// * 通过结果集原信息对象获取列数
int columnCount = metaData.getColumnCount();
//* 通过循环遍历列数
for (int i = 1; i <= columnCount; i++) {
// * 通过结果集源信息获取列名
String columnName = metaData.getColumnName(i);
// 通过列名获取该列数据
Object value = resultSet.getObject(columnName);
//* 创建属性描述器对象,将获取到的值通过对象的set()方法进行赋值
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName.toLowerCase(), beanClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(bean, value);
}
//* 将封装好的对象添加到集合中
list.add(bean);
}
// * 返回集合对象
} catch (Exception throwables) {
throwables.printStackTrace();
}
return list;
}
}
2.queryForList
public <T> List<T> queryForList(String sql, ResultSetHandler<T> resultSetHandler , Object... objects){
// 创建list集合
List<T> list = new ArrayList<>();
try {
//通过数据源获取一个数据库连接
connection = dataSource.getConnection();
//通过数据库连接对象获取执行者对象,并对sql语句进行预编译
preparedStatement = connection.prepareStatement(sql);
// 通过执行者对象获取参数的源信息对象
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
//通过通过参数源信息对象获取参数个数
int parameterCount = parameterMetaData.getParameterCount();
//判断参数数量是否一致
if(parameterCount != objects.length){
throw new RuntimeException("参数个数不匹配");
}
//为占位符赋值
for (int i=0; i<objects.length; i++){
preparedStatement.setObject(i+1,objects[i]);
}
//执行sql语句并接受结果
resultSet = preparedStatement.executeQuery();
// 通过BeanListHandler方法对结果集进行处理
list = (List<T>) resultSetHandler.handler(resultSet);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放资源
DataSourceUtils.close(connection,preparedStatement,resultSet);
}
//返回结果
return list;
}
4)queryForScalar 返回集合函数结果
1.ScalarHandler
-
定义ScalarHandler< T > 实现ResultSetHandler< T>接口
-
重写handler()方法,用于返回一个聚合函数的查询结果
-
定义Long类型变量
-
判断结果集是否有数据
-
通过结果集对象获取结果集源信息的对象
-
通过结果集源信息对象获取第一列的列名
-
通过列名获取该列的数据
-
将结果集返回
//* 定义ScalarHandler< T > 实现ResultSetHandler< T>接口 public class ScalarHandler<T> implements ResultSetHandler<T>{ //* 重写handler()方法,用于返回一个聚合函数的查询结果 @Override public Long handler(ResultSet resultSet) { //* 定义Long类型变量 Long value = null; try { //* 判断结果集是否有数据 if (resultSet.next()){ //* 通过结果集对象获取结果集源信息的对象 ResultSetMetaData metaData = resultSet.getMetaData(); //* 通过结果集源信息对象获取第一列的列名 String columnName = metaData.getColumnName(1); //* 通过列名获取该列的数据 value = resultSet.getLong(columnName); } } catch (SQLException throwables) { throwables.printStackTrace(); } //* 将结果集返回 return value; } }
2.queryForScalar
public Long queryForScalar(String sql, ResultSetHandler<Long> resultSetHandler , Object... objects){ // 创建Long类型变量 Long value = null; try { //通过数据源获取一个数据库连接 connection = dataSource.getConnection(); //通过数据库连接对象获取执行者对象,并对sql语句进行预编译 preparedStatement = connection.prepareStatement(sql); // 通过执行者对象获取参数的源信息对象 ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData(); //通过通过参数源信息对象获取参数个数 int parameterCount = parameterMetaData.getParameterCount(); //判断参数数量是否一致 if(parameterCount != objects.length){ throw new RuntimeException("参数个数不匹配"); } //为占位符赋值 for (int i=0; i<objects.length; i++){ preparedStatement.setObject(i+1,objects[i]); } //执行sql语句并接受结果 resultSet = preparedStatement.executeQuery(); // 通过BeanListHandler方法对结果集进行处理 value = resultSetHandler.handler(resultSet); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { //释放资源 DataSourceUtils.close(connection,preparedStatement,resultSet); } //返回结果 return value; }