简介
上篇文章大致写了JDBC连接数据库的步骤,可是每次都这么来一遍,着实麻烦。所以我们干脆把它封装起来。以后要用直接调用即可啦。
代码实现
1、加载驱动的封装
对于驱动加载,我们从头到尾只用执行一次。所以,我们可以模仿别人的写法把它放在静态代码块里面:
public class DBUtil {
private static final String DB_DEIVER = "com.mysql.jdbc.Driver";
private static final String DB_URL = "jdbc:mysql://my.mcdd.top:3306/test";
private static final String DB_USER = "root";
private static final String DB_PWD = "m147258369";
private static Connection connection;
/**
* 加载驱动
*/
static {
try {
Class.forName(DB_DEIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2、连接数据库封装
对于连接数据库,我们不要一开始就连接上了,因为那样太耗费资源了。所以可以封装成函数,然后在构造函数传值之后调用,这样每次new
对象的时候,就会自动连接数据库啦。
连接数据库代码:
/**
* 连接数据库
*/
public void getConnection(){
try {
connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void getConnection(String url, String user, String pwd){
try {
connection = DriverManager.getConnection(url, user, pwd);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
哈哈,当然是俩份啦,传参就用传入值,不传的话,就用默认值。
然后编写构造函数:
/**
* 构造函数
*/
public DBUtil() {
getConnection();
}
public DBUtil(String url, String user, String pwd) {
getConnection(url, user, pwd);
}
同样俩份。
3、查询语句封装
思路:从数据库拿到值之后,利用反射创建实体类,然后进行属性赋值。
/**
* 查询语句封装,返回值根据实体类成员名称进行赋值
* @param sql sql语句
* @param args 参数,用List传
* @param tClass 返回值列表里的成员类型
* @return 返回查询结果的List
*/
public <T> List<T> selectResultByName(String sql, List<?> args, Class<T> tClass){
List<T> resList = new ArrayList<>();
try {
// 利用反射获取属性
Field[] declaredFields = tClass.getDeclaredFields();
// 创建语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 赋值参数
for (int i = 0; i < args.size(); i++) {
preparedStatement.setObject(i+1, args.get(i));
}
// 执行语句
ResultSet resultSet = preparedStatement.executeQuery();
// 获取返回值的表数据和它的长度
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
// 反射构建类
Object res = tClass.getDeclaredConstructor().newInstance();
for (Field declaredField : declaredFields) {
Object object = resultSet.getObject(declaredField.getName());
declaredField.setAccessible(true);
declaredField.set(res, object);
}
resList.add((T) res);
}
preparedStatement.close();
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return resList;
}
这里要注意的是,我们采用的赋值方法是从传入类型的成员变量中拿到属性名,再用这个属性名去找result中的对应值,最后赋值。
但是也有一种可能,数据库的值和实体类对不上,我们赋值采用顺序赋值,所以:
/**
* 查询语句封装,返回值根据实体类成员顺序进行赋值
* @param sql sql语句
* @param args 参数,用List传
* @param tClass 返回值列表里的成员类型
* @return 返回查询结果的List
*/
public <T> List<T> selectResultByOrder(String sql, List<?> args, Class<T> tClass){
List<T> resList = new ArrayList<>();
int columLen;
try {
// 利用反射获取属性
Field[] declaredFields = tClass.getDeclaredFields();
// 创建语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 赋值参数
for (int i = 0; i < args.size(); i++) {
preparedStatement.setObject(i+1, args.get(i));
}
// 执行语句
ResultSet resultSet = preparedStatement.executeQuery();
// 获取返回值的表数据和它的长度
ResultSetMetaData metaData = resultSet.getMetaData();
columLen = metaData.getColumnCount();
while (resultSet.next()) {
// 反射构建类
Object res = tClass.getDeclaredConstructor().newInstance();
// 遍历resultSet的每个属性值
for (int i = 0; i < columLen; i++) {
// 获取每一个返回对象的参数名
String columnName = metaData.getColumnName(i + 1);
// 获取对应名的参数
Object object = resultSet.getObject(columnName);
// 利用反射给res赋值参数
declaredFields[i].setAccessible(true);
declaredFields[i].set(res, object);
}
resList.add((T) res);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return resList;
}
关闭连接
这个简单:
/**
* 关闭连接
*/
public void close(){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
最后
最后贴上我们最终的代码:
package com.sy;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author :byMJC
* @date :Created 2022/1/14 20:48
* @description:my DBUtil
*/
public class DBUtil {
private static final String DB_DEIVER = "com.mysql.jdbc.Driver";
private static String DB_URL = "jdbc:mysql://my.mcdd.top:3306/test";
private static String DB_USER = "root";
private static String DB_PWD = "m147258369";
private static Connection connection;
/**
* 加载驱动
*/
static {
try {
Class.forName(DB_DEIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 连接数据库
*/
public void getConnection(String url, String user, String pwd){
try {
connection = DriverManager.getConnection(url, user, pwd);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 构造函数
*/
public DBUtil() {
getConnection(DB_URL, DB_USER, DB_PWD);
}
public DBUtil(String url, String user, String pwd) {
DB_URL = url;
DB_USER = user;
DB_PWD = pwd;
getConnection(DB_URL, DB_USER, DB_PWD);
}
/**
* 查询语句封装,返回值根据实体类成员顺序进行赋值
* @param sql sql语句
* @param args 参数,用List传
* @param tClass 返回值列表里的成员类型
* @return 返回查询结果的List
*/
public <T> List<T> selectResultByOrder(String sql, List<?> args, Class<T> tClass){
List<T> resList = new ArrayList<>();
int columLen;
try {
if (connection.isClosed()) {
getConnection(DB_URL, DB_USER, DB_PWD);
}
// 利用反射获取属性
Field[] declaredFields = tClass.getDeclaredFields();
// 创建语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 赋值参数
for (int i = 0; i < args.size(); i++) {
preparedStatement.setObject(i+1, args.get(i));
}
// 执行语句
ResultSet resultSet = preparedStatement.executeQuery();
// 获取返回值的表数据和它的长度
ResultSetMetaData metaData = resultSet.getMetaData();
columLen = metaData.getColumnCount();
while (resultSet.next()) {
// 反射构建类
Object res = tClass.getDeclaredConstructor().newInstance();
// 遍历resultSet的每个属性值
for (int i = 0; i < columLen; i++) {
// 获取每一个返回对象的参数名
String columnName = metaData.getColumnName(i + 1);
// 获取对应名的参数
Object object = resultSet.getObject(columnName);
// 利用反射给res赋值参数
declaredFields[i].setAccessible(true);
declaredFields[i].set(res, object);
}
resList.add((T) res);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return resList;
}
/**
* 查询语句封装,返回值根据实体类成员名称进行赋值
* @param sql sql语句
* @param args 参数,用List传
* @param tClass 返回值列表里的成员类型
* @return 返回查询结果的List
*/
public <T> List<T> selectResultByName(String sql, List<?> args, Class<T> tClass){
List<T> resList = new ArrayList<>();
try {
if (connection.isClosed()) {
getConnection(DB_URL, DB_USER, DB_PWD);
}
// 利用反射获取属性
Field[] declaredFields = tClass.getDeclaredFields();
// 创建语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 赋值参数
for (int i = 0; i < args.size(); i++) {
preparedStatement.setObject(i+1, args.get(i));
}
// 执行语句
ResultSet resultSet = preparedStatement.executeQuery();
// 获取返回值的表数据和它的长度
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
// 反射构建类
Object res = tClass.getDeclaredConstructor().newInstance();
for (Field declaredField : declaredFields) {
Object object = resultSet.getObject(declaredField.getName());
declaredField.setAccessible(true);
declaredField.set(res, object);
}
resList.add((T) res);
}
preparedStatement.close();
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return resList;
}
/**
* 关闭连接
*/
public void close(){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
代码和之前的又有一点点不同,因为我们还要考虑到一种情况,如果用户已经关闭连接了,但是又要进行数据库操作了怎么办?所以我在每条语句前面都加了个检测数据库连接,并且自动连接。