一,连接数据库
1. 连接mysql数据库
Connection conn = null;
//数据库连接驱动名:针对不同的数据库,驱动名称不同,但是同一种类型的数据库改字符串相同
Class.forName("com.mysql.jdbc.Driver");
String url="JDBC:mysql://localhost:8080/testDB";
String user="test";
String password="test";
try {
//1.加载驱动
Class.forName(driver );
//2.连接
conn = DriverManager.getConnection(url, user, password);
System.out.println("连接数据库成功!");
PreparedStatement statement = null;
//举个查询例子测试一下
//查询userinfo表的数据
statement = conn .prepareStatement("select * from userInfo");
ResultSet res = null;
res = statement.executeQuery();
//当查询下一行有记录时:res.next()返回值为true,反之为false
while (res.next()) {
String TenantCode = res.getString("TenantCode");
String TenantName = res.getString("TenantName");
String Cloud = res.getString("Cloud");
System.out.println("学号:" + TenantCode + "姓名:" + TenantName + " 性别:" + Cloud);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接数据库失败!");
}
2.连接sqlserver数据库
Connection conn = null;
Class.forName("com.microsoft.JDBC.sqlserver.SQLServerDriver");
String url="JDBC:microsoft:sqlserver://localhost:1433;DatabaseName=testDb";
String user="test";
String password="test";
try {
//1.加载驱动
Class.forName(driver );
//2.连接
conn = DriverManager.getConnection(url, user, password);
System.out.println("连接数据库成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接数据库失败!");
}
3. 连接postgresql数据库
Connection conn = null;
//数据库连接驱动名:针对不同的数据库,驱动名称不同,但是同一种类型的数据库改字符串相同
Class.forName("org.postgresql.Driver");
String url="JDBC:postgresql://localhost/testDb";
String user="test";
String password="test";
try {
//1.加载驱动
Class.forName(driver );
//2.连接
conn = DriverManager.getConnection(url, user, password);
System.out.println("连接数据库成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接数据库失败!");
}
4. 连接Oracle 数据库
Connection conn = null;
Class.forName("oracle.JDBC.driver.OracleDriver");
String url="JDBC:oracle:thin:@localhost:1521:orcl"//orcl为Oracle数据库的SID
String user="test";
String password="test";
try {
//1.加载驱动
Class.forName(driver );
//2.连接
conn = DriverManager.getConnection(url, user, password);
System.out.println("连接数据库成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接数据库失败!");
}
二. JDBCUtils(数据库常用操作工具类)
(1)获取数据库连接对象
(2)获取查询结果集
(3)将查询结果集转化为指定对象(使用者自行提供类参数,通过反射和转化)
(4)执行更新、删除、插入操作
(5)关闭数据库连接
package utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 数据库常用操作工具类
*
*/
public final class JdbcUtils {
// mysql8驱动
public static final String MYSQL8_DRIVER = "com.mysql.cj.jdbc.Driver";
/**
* 结果集处理器
*
*/
public static interface ResultSetHandler<T> {
/**
* 将一个结果集转换成T类型
*
* @param rs
* @return
*/
T handle(ResultSet rs);
}
/**
* 列处理器
*
*/
public static interface ColumnHandler<T> {
/**
*
* @param method 根据列名自动匹配的方法名
* @param columnName 列名
* @param t 对象
* @param value 值
* @return 返回true,表示用户已处理完成,无需再处理,返回false,则代表用户不处理
*/
boolean handleColumn(Method method, String columnName, T t, Object value);
}
/**
* 内部类的目的,就是为了将结果集中的数据自动封装成对象
*
*/
public static class BeanListHandler<T> implements ResultSetHandler<List<T>> {
private final Class<T> clazz;
private ColumnHandler<T> columnHandler;
public BeanListHandler(Class<T> clazz) {
this.clazz = clazz;
}
public BeanListHandler(Class<T> clazz, ColumnHandler<T> columnHandler) {
this.clazz = clazz;
this.columnHandler = columnHandler;
}
@Override
public List<T> handle(ResultSet rs) {
// 返回值
List<T> list = new ArrayList<>();
// 存储所有列名(别名)
List<String> columnNames = new ArrayList<>();
// 存储所有方法,键名是列名(别名),值即其对应的setter方法
Map<String, Method> methodMap = new HashMap<>();
// 获取所有列名
try {
// 结果集元数据
ResultSetMetaData rsmd = rs.getMetaData();
// 返回查询结果集的列数
int count = rsmd.getColumnCount();
// 返回此类型的所有方法
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < count; i++) {
// 获取列名,如果起别名,则获取别名
String columnName = rsmd.getColumnLabel(i + 1);
columnNames.add(columnName);// 返回查询结果集的列名
// 组装出对象的方法名
String methodName = columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
methodName = "set" + methodName;
for (Method me : methods) {
if (me.getName().equals(methodName)) {
methodMap.put(columnName, me);// 设置到map中
break;
}
}
}
// 准备工作已完成,将结果集中的数据转换成T类型的实例
if (rs != null) {
// 获取无参的构造方法
Constructor<T> con = clazz.getDeclaredConstructor();
while (rs.next()) {
T t = con.newInstance();// T类型的实例
for (int i = 0; i < count; i++) {
String columnName = columnNames.get(i);
// 从结果集中取出对应列的数据
Object value = rs.getObject(columnName);
// 取出方法
Method method = methodMap.get(columnName);
if (method != null) {
if (columnHandler != null) {
boolean done = columnHandler.handleColumn(method, columnName, t, value);
if (!done) {
// 通过反射给T类型的实例赋值
method.invoke(t, value);
}
}
}
}
list.add(t);
}
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/**
* 获取数据库连接
*
* @param url
* @param user
* @param password
* @return
*/
public static final Connection getConnection(String driver, String url, String user, String password) {
try {
Class.forName(driver);
return DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
throw new RuntimeException("无法创建数据库连接");
}
/**
* 获取数据库连接
*
* @param url
* @param user
* @param password
* @return
*/
public static final Connection getConnection(String url, String user, String password) {
return getConnection(MYSQL8_DRIVER, url, user, password);
}
/**
* 执行查询操作,返回结果集
*
* @param conn
* @param sql
* @param args
* @return
*/
private static final ResultSet query(Connection conn, String sql, Object[] args) {
try {
PreparedStatement ps = conn.prepareStatement(sql);
if (args != null) {
// 给PreparedStatement实例设置参数
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
}
return ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
throw new RuntimeException("查询出现异常");
}
/**
* 返回对象的集合
*
* @param <T>
* @param conn
* @param sql
* @param args
* @return
*/
public static final <T> T query(Connection conn, ResultSetHandler<T> handler, String sql, Object[] args) {
ResultSet rs = query(conn, sql, args);
return handler.handle(rs);
}
/**
* 写操作
*
* @return 返回受影响的行数
*/
public static final int update(Connection conn, String sql, Object[] args) {
try {
PreparedStatement ps = conn.prepareStatement(sql);
if (args != null) {
// 给PreparedStatement实例设置参数
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
}
return ps.executeUpdate();
} catch (SQLException e) {
// e.printStackTrace();
}
return -1;
}
/**
* 关闭数据库连接
*
* @param conn
*/
public static final void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
二.二、自定义JDBCUtils
我采用的是:
-
JDBCUtils来连接和关闭数据库相关资源
。 - 再写一个
类(BeanJDBCUtils)来进行数据库的基本操作
。 - 最后写一个类来实现具体的操作。
1. JDBCUtils
/**
* @author long
* @date 2022/6/15 14:00
* @Description: 连接数据库的类
*/
@SuppressWarnings("all")
public class JDBCUtils {
private static final String url;
private static final String userName;
private static final String password;
private static final String driver;
static {
Properties properties = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(is);
url = properties.getProperty("url");
userName = properties.getProperty("userName");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
//注册驱动
Class.forName(driver);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 获取数据库的连接
* @return
*/
public Connection getConnection() {
try {
return DriverManager.getConnection(url, userName, password);
} catch (SQLException e) {
throw new RuntimeException("无法连接到数据库\n");
}
}
/**
* @Description 关闭连接
* @param connection
*/
public void close(Connection connection) {
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* @Description 关闭连接
* @param connection
*/
public void close(Connection connection, ResultSet resultSet) {
try {
connection.close();
resultSet.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
2. BeanJDBCUtils
/**
* @author long
* @date 2022/6/15 15:23
* @Description: 对数据的操作的基本类
*/
@SuppressWarnings("all")
public class BeanJDBCUtils<T> extends JDBCUtils {
private Connection connection;
private PreparedStatement preparedStatement;
private Class entityClass;
/**
* 构造方法,为了获取到泛型的对象的类,将其赋值给entityClass
*/
public BeanJDBCUtils() {
//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
//所以getGenericSuperclass()获取到的是BaseJDBCUtils的Class
//System.out.println("获取父类对象:" + clazz.getSuperclass());
Type genericType = getClass().getGenericSuperclass();
//ParameterizedType 参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
//获取到的<T>中的T的真实的类型
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* @param sql
* @param args
* @return
* @Description: 查找数据库中多行数据
*/
public List<T> query(String sql, Object... args) {
List<T> list = new ArrayList<>();
connection = getConnection();
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
/*填充占位符*/
for (int i = 0; i < args.length; ++i)
preparedStatement.setObject(i + 1, args[i]);
preparedStatement.execute();
/*获取返回结果*/
resultSet = preparedStatement.getResultSet();
/*获取返回结果的数据*/
ResultSetMetaData metaData = resultSet.getMetaData();
/*获取数据的行数*/
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
/*初始化泛型*/
T entity = (T) entityClass.newInstance();
Object object = new Object();
for (int i = 0; i < columnCount; ++i) {
/*获取列名的别名,如果没有别名则直接获取列名*/
String columnLabel = metaData.getColumnLabel(i + 1);
object = resultSet.getObject(i + 1);
/*使用反射给泛型变量赋值*/
Field field = entity.getClass().getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(entity, object);
}
list.add(entity);
}
return list;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
close(connection, resultSet);
}
}
/**
*
* @param sql
* @param clazz
* @param args
* @return
* @Description: 查找数据库中单行数据
*/
public T query(String sql, Class clazz, Object... args) {
connection = getConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; ++i)
preparedStatement.setObject(i + 1, args[i]);
resultSet = preparedStatement.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
T t = (T) entityClass.newInstance();
if (resultSet.next()) {
Object object = new Object();
for (int i = 0; i < columnCount; i++) {
String columnLabel = metaData.getColumnLabel(i + 1);
Field field = t.getClass().getDeclaredField(columnLabel);
field.setAccessible(true);
object = resultSet.getObject(columnLabel);
field.set(t, object);
}
}
return t;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
close(connection, resultSet);
}
}
/**
* @param sql
* @param args
* @return 影响的行数
* @Description: 增删改
*/
public Integer updata(String sql, Object... args) {
connection = getConnection();
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; ++i)
preparedStatement.setObject(i + 1, args[i]);
return preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
close(connection);
}
}
/**
* @param sql
* @param args
* @param <E>
* @return
* @Description: 查找特定的值,并返回单一基本类型
*/
public <E> E getElement(String sql, Object... args) {
connection = getConnection();
ResultSet resultSet = null;
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
Object object = null;
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
object = resultSet.getObject(1);
}
return (E) object;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
close(connection, resultSet);
}
}
}
创建一个与数据库表t_fruit一一对应的Fruit类
import lombok.*;
/**
* @author long
* @date 2022/6/15 14:58
* @Description: 与数据库中的t_fruit表一一对应的水果类
*/
@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuppressWarnings("all")
public class Fruit {
private Integer fid;
private String fname;
private Integer price;
private Integer fcount;
private String remark;
public Fruit(String fname, Integer price, Integer fcount, String remark) {
this.fname = fname;
this.price = price;
this.fcount = fcount;
this.remark = remark;
}
}
创建一个接口(FruitDAO)来声明对改数据库的表中的操作的方法。
import java.util.List;
public interface FruitDAO {
/*获取所有水果信息*/
List<Fruit> getAllFruit();
/*添加水果信息*/
Integer addFruit(Fruit fruit);
/*获取水果的种类的数量*/
Long getAllCount();
/*获取最大价格*/
Integer getMaxPrice();
/*获取最小价格*/
Integer getMinPrice();
Fruit getFruitById(Integer id);
}
对上述接口(FruitDAO)的实现类(FruitDAOImpl)
/**
* @author long
* @date 2022/6/15 15:04
* @Description: 对数据库中t_fruit表的操作的类
*/
public class FruitDAOImpl extends BeanJDBCUtils<Fruit> implements FruitDAO {
@Override
public List<Fruit> getAllFruit() {
String sql = "select * from t_fruit";
return query(sql);
}
@Override
public Integer addFruit(Fruit fruit) {
String sql = "insert into t_fruit(fname,price,fcount,remark) values(?,?,?,?)";
return updata(sql, fruit.getFname(), fruit.getPrice(), fruit.getFcount(), fruit.getRemark());
}
@Override
public Long getAllCount() {
String sql = "select count(*) from t_fruit";
return getElement(sql);
}
@Override
public Integer getMaxPrice() {
String sql = "select max(price) from t_fruit";
return getElement(sql);
}
@Override
public Integer getMinPrice() {
String sql = "select min(price) from t_fruit";
return getElement(sql);
}
@Override
public Fruit getFruitById(Integer id) {
String sql = "select * from t_fruit where fid = ?";
return query(sql, Fruit.class, id);
}
}