本篇文章以 MySQL 数据库为例,若要切换其他数据库,只需修改 resource文件夹中的 jdbc.properties 配置文件即可。
项目架构展示:
将MySQL驱动包导入到 lib 目录下,导入之后右键 AS library 将驱动包添加到项目中。否则运行时会报 Class not found 异常。
驱动包下载地址汇总:https://blog.csdn.net/weixin_43671437/article/details/134141851?spm=1001.2014.3001.5501
在Resource 目录下创建 jdbc.properties 配置文件。
## MySQL 8.x
user=root
password=root
url=jdbc:mysql://localhost:3306/jdbc_learn?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
driverClass=com.mysql.cj.jdbc.Driver
## SQLServer 连接属性
#url=jdbc:sqlserver://localhost:1433;DatabaseName=SqlMatch2005_5;encrypt=true;trustServerCertificate=true
#driverClass=com.microsoft.sqlserver.jdbc.SQLServerDriver
#user=sa
#password=root
在 java --> util 包内创建一个 JDBCUtil.java 工具类
/**
* ClassName: JDBCUtil
* Description: 操作数据库的工具类
*
* @Create 2023/10/29 14:35
* @Version 1.0
*/
public class JDBCUtil {
/*
获取数据库连接
*/
public static Connection getConnection() throws Exception {
// 1 读取配置文件中的4个信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
// 2 加载驱动
Class.forName(driverClass);
// 3 获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* 关闭资源操作,增删改时使用
* @param conn
* @param ps
*/
public static void closeResource(Connection conn, Statement ps){
// 7 资源关闭
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭资源的操作,查询时使用
* @param conn
* @param ps
* @param rs
*/
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
// 7 资源关闭
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
测试成功,可以返回一个连接。
@Test
public void testConnection6() throws Exception {
Connection conn = JDBCUtil.getConnection();
System.out.println(conn); // com.mysql.cj.jdbc.ConnectionImpl@1cbbffcd
JDBCUtil.closeResource(conn,null);
}
创建 BaseDao.java 类,可直接继承baseDao 来实现对数据库的增删改查。
/**
* ClassName: BaseDao
* Description: DAO: data(base) access object 数据库访问对象
* 封装了针对于数据表的增删改查操作
*
* @Create 2023/11/1 13:46
* @Version 1.0
*/
public abstract class BaseDao<T> {
private Class<T> clazz = null;
{
// 获取当前BaseDao的子类继承父类的泛型
Type genericSuperclass = this.getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType)genericSuperclass; // 获取了父类的泛型参数
Type[] typeArguments = paramType.getActualTypeArguments();
clazz = (Class<T>) typeArguments[0]; // 泛型的第一个参数
}
/**
* 通用表的查询方法,但仅能查询条数据
*
* @param conn
* @param sql
* @param args
* @return 返回一个对象
*/
public T getInstance(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// 为参数赋值
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[0]);
}
// 获取结果集
rs = ps.executeQuery();
// 获取结果集的元数据:ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
// 处理结果集中的每一列
for (int i = 0; i < columnCount; i++) {
// 获取每一列的列值 通过 ResultSet
Object columnValue = rs.getObject(i + 1);
// 获取每一列的列名 通过 ResultSetMetaData
// 获取列的列名 getColumnName() -- 不推荐使用
// 获取列的别名 getColumnLabel() 没有别名时返回列名
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给T对象指定columnName属性,赋值为columnValue,通过反射
// 通俗点说:将customer中的属性与 列名 对应起来 并为属性赋值
// 注意;若属性为orderID 列名order_id 此时需要为列名起别名使与属性名一致
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnValue); // 赋值
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源关闭
JDBCUtil.closeResource(null, ps, rs);
}
return null;
}
/**
* 通用表的查询操作,可返回多条数据。
*
* @param conn
* @param sql
* @param args
* @return 返回一个对象集合
*/
public List<T> getForList(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// 为参数赋值
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[0]);
}
// 获取结果集
rs = ps.executeQuery();
// 获取结果集的元数据:ResultSetMetaData
ResultSetMetaData rsmd = rs.getMetaData();
// 通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
// 创建集合对象 存储查询的结果
ArrayList<T> list = new ArrayList<>();
// 循环遍历每一行数据
while (rs.next()) {
T t = clazz.newInstance();
// 处理结果集中的每一列
for (int i = 0; i < columnCount; i++) {
// 获取每一列的列值 通过 ResultSet
Object columnValue = rs.getObject(i + 1);
// 获取每一列的列名 通过 ResultSetMetaData
// 获取列的列名 getColumnName() -- 不推荐使用
// 获取列的别名 getColumnLabel() 没有别名时返回列名
String columnLabel = rsmd.getColumnLabel(i + 1);
// 给T对象指定columnName属性,赋值为columnValue,通过反射
// 通俗点说:将customer中的属性与 列名 对应起来 并为属性赋值
// 注意;若属性为orderID 列名order_id 此时需要为列名起别名使与属性名一致
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnValue); // 赋值
}
list.add(t);
}
// 返回数据集合
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
// 资源关闭
JDBCUtil.closeResource(null, ps, rs);
}
return null;
}
/**
* 通用的 增删改 操作-- version 2.0 增加事务
*
* @param conn
* @param sql
* @param args
* @return
*/
public int updateTable(Connection conn, String sql, Object... args) { // sql中占位符的个数与可变形参的个数相同
PreparedStatement ps = null;
try {
// 2 预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 3 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]); // 注意参数错误,sql中是从1 开始 数组从0开始
}
// 4 执行sql语句
// boolean execute = ps.execute();
// if (!execute) System.out.println("执行成功!!!");
// 返回影响了几行数据
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 修改起为自动提交
// 主要针对于使用数据库连接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
throw new RuntimeException(e);
}
// 5 资源关闭
JDBCUtil.closeResource(null, ps);
}
return 0;
}
/**
* 用于查询特殊值的通用方法
* @param conn
* @param sql
* @param args
* @return
* @param
*/
public <E> E getValue(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
// 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 获取查询结果
rs = ps.executeQuery();
if (rs.next()) {
return (E) rs.getObject(1);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(null, ps, rs);
}
return null;
}
}
在Dao层实现对 Customers 类的增删改查以及特殊值的查询
1 创建 CustomersDao.java 接口
/**
* ClassName: CustomersDao
* Description: 此接口用于规范 Customers 表的常用操作
*
* @Create 2023/11/1 14:06
* @Version 1.0
*
*/
public interface CustomersDao {
/**
* 将cust对象添加到数据库中
* @param conn
* @param cust
*/
void insert(Connection conn, Customer cust);
/**
* 针对指定的id,删除表中的一条记录
* @param conn
* @param id
*/
void deleteById(Connection conn, int id);
/**
* 针对内存中的cust对象,去修改数据表中指定的记录
* @param conn
* @param cust
*/
void update(Connection conn, Customer cust);
/**
* 根据指定 ID 查询到对象的Customer对象
* @param conn
* @param id
* @return
*/
Customer getCustomerById(Connection conn,int id);
/**
* 返回所有 Customer 对象
* @param conn
* @return
*/
List<Customer> getAllCustomers(Connection conn);
/**
* 返回数据表中数据的条目
* @param conn
* @return
*/
Long getCount(Connection conn);
/**
* 返回表中最大的生日
* @param conn
* @return
*/
Date getMaxBirth(Connection conn);
}
2 编写CustomersDao接口的实现类
创建 CustomerDaoImpl.java 文件,继承BaseDao并实现CustomersDao接口。
/**
* ClassName: CustomerDaoImpl
* Description:
*
* @Create 2023/11/1 14:48
* @Version 1.0
*/
public class CustomerDaoImpl extends BaseDao<Customer> implements CustomersDao {
@Override
public void insert(Connection conn, Customer cust) {
String sql = "insert into customers(name,email,birth) values(?,?,?) ";
updateTable(conn, sql, cust.getName(), cust.getEmail(), cust.getBirth());
}
@Override
public void deleteById(Connection conn, int id) {
String sql = "delete from customers where id = ?";
updateTable(conn, sql, id);
}
@Override
public void update(Connection conn, Customer cust) {
String sql = "update customers set name = ?, email = ?, birth = ? where id = ?";
updateTable(conn, sql, cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
}
@Override
public Customer getCustomerById(Connection conn, int id) {
String sql = "select id, name,email,birth from customers where id = ?";
return getInstance(conn, sql, id);
}
@Override
public List<Customer> getAllCustomers(Connection conn) {
String sql = "select id, name,email,birth from customers";
return getForList(conn, sql);
}
@Override
public Long getCount(Connection conn) {
String sql = "select count(*) from customers";
return getValue(conn,sql);
}
@Override
public Date getMaxBirth(Connection conn) {
String sql = "select max(birth) from customers";
return getValue(conn,sql);
}
}
创建测试类 CustomerDaoImplTest 测试 CustomerDaoImpl
/**
* ClassName: CustomerDaoImplTest
* Description:
*
* @Create 2023/11/1 15:18
* @Version 1.0
*/
public class CustomerDaoImplTest {
private CustomerDaoImpl dao = new CustomerDaoImpl();
@Test
public void insert() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
Customer cust = new Customer(1,"songsong","[email protected]",new Date(21312425312L));
dao.insert(conn,cust);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void deleteById() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
dao.deleteById(conn,2);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void update() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
Customer cust = new Customer(1,"songsong","[email protected]",new Date(21312425312L));
dao.update(conn,cust);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void getCustomerById() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
System.out.println(dao.getCustomerById(conn, 4));
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void getAllCustomers() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
List<Customer> customerList = dao.getAllCustomers(conn);
customerList.forEach(System.out::println);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void getCount() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
System.out.println(dao.getCount(conn));
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
@Test
public void getMaxBirth() {
Connection conn = null;
try {
conn = JDBCUtil.getConnection();
System.out.println(dao.getMaxBirth(conn));
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtil.closeResource(conn,null);
}
}
}