java 数据库basedao
时间: 2025-08-19 14:07:50 浏览: 1
<think>我们即将实现一个通用的BaseDao,用于简化数据库操作。BaseDao将提供基本的CRUD操作,并支持泛型,以便用于不同的实体类。
我们将使用JDBC来实现,但为了简化代码,我们将使用一些设计模式(如模板方法)来减少重复代码。
注意:为了简化示例,我们不会处理所有异常和资源关闭的最佳实践,但在生产环境中需要完善。
步骤:
1. 定义一个BaseDao接口,声明基本的CRUD方法。
2. 创建一个BaseDaoImpl实现类,使用JDBC实现这些方法。
3. 使用泛型来支持不同的实体类型。
4. 使用反射来动态设置查询参数和映射结果集到实体对象。
我们将假设每个实体类都有一个Long类型的id字段。
代码结构:
- 定义接口BaseDao<T>
- 实现类BaseDaoImpl<T> implements BaseDao<T>
- 需要注入DataSource(这里我们通过构造函数传入)
注意:为了简化,我们不会使用连接池,但实际应用中应该使用。
我们将实现以下方法:
- T save(T entity) // 插入
- T update(T entity) // 更新
- void delete(Long id) // 删除
- T findById(Long id) // 根据id查询
- List<T> findAll() // 查询所有
为了构建SQL语句,我们需要知道表名和字段名。这里我们假设表名与类名相同(小写),字段名与属性名相同(驼峰转下划线)。
但实际中可能会使用注解来指定,这里为了简化,我们使用约定。
另外,我们假设每个实体类都有一个@Id注解来标识主键字段(这里我们自己定义一个Id注解)。
由于时间关系,我们只实现save和findById方法,其他方法类似。
首先,我们定义一个Id注解:</think>### Java 数据库通用 BaseDAO 实现方案
以下是一个完整的基于 JDBC 的通用 BaseDAO 实现,包含泛型支持、事务管理和连接池集成:
#### 1. 核心接口设计
```java
/**
* 通用 DAO 接口
* @param <T> 实体类型
* @param <ID> 主键类型
*/
public interface BaseDao<T, ID> {
T findById(ID id) throws SQLException;
List<T> findAll() throws SQLException;
ID save(T entity) throws SQLException;
void update(T entity) throws SQLException;
void delete(ID id) throws SQLException;
List<T> findByCriteria(String whereClause, Object... params) throws SQLException;
}
```
#### 2. 抽象 BaseDAO 实现
```java
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;
/**
* 基于 JDBC 的通用 DAO 实现
* @param <T> 实体类型
* @param <ID> 主键类型
*/
public abstract class AbstractJdbcDao<T, ID> implements BaseDao<T, ID> {
private final Class<T> entityClass;
private final DataSource dataSource;
public AbstractJdbcDao(Class<T> entityClass, DataSource dataSource) {
this.entityClass = entityClass;
this.dataSource = dataSource;
}
// 获取表名(可被子类覆盖)
protected String getTableName() {
return entityClass.getSimpleName().toLowerCase();
}
// 获取主键字段名(可被子类覆盖)
protected String getIdColumnName() {
return "id";
}
// 获取所有字段(排除主键)
protected List<String> getColumnNames() {
List<String> columns = new ArrayList<>();
for (Field field : entityClass.getDeclaredFields()) {
if (!field.getName().equalsIgnoreCase(getIdColumnName())) {
columns.add(field.getName());
}
}
return columns;
}
// 映射结果集到实体对象
protected T mapResultSetToEntity(ResultSet rs) throws SQLException {
try {
T entity = entityClass.getDeclaredConstructor().newInstance();
for (Field field : entityClass.getDeclaredFields()) {
field.setAccessible(true);
String columnName = convertToSnakeCase(field.getName());
Object value = rs.getObject(columnName);
field.set(entity, value);
}
return entity;
} catch (Exception e) {
throw new SQLException("Mapping failed", e);
}
}
// 驼峰转蛇形命名
private String convertToSnakeCase(String camelCase) {
return camelCase.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase();
}
// 获取数据库连接
protected Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 关闭资源
protected void closeResources(Connection conn, PreparedStatement ps, ResultSet rs) {
try {
if (rs != null) rs.close();
if (ps != null) ps.close();
if (conn != null) conn.close();
} catch (SQLException e) {
// 记录日志
}
}
// === 核心方法实现 ===
@Override
public T findById(ID id) throws SQLException {
String sql = "SELECT * FROM " + getTableName() + " WHERE " + getIdColumnName() + " = ?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConnection();
ps = conn.prepareStatement(sql);
ps.setObject(1, id);
rs = ps.executeQuery();
if (rs.next()) {
return mapResultSetToEntity(rs);
}
return null;
} finally {
closeResources(conn, ps, rs);
}
}
@Override
public List<T> findAll() throws SQLException {
String sql = "SELECT * FROM " + getTableName();
return executeQuery(sql);
}
@Override
public ID save(T entity) throws SQLException {
List<String> columns = getColumnNames();
String columnNames = String.join(", ", columns);
String placeholders = String.join(", ", Collections.nCopies(columns.size(), "?"));
String sql = "INSERT INTO " + getTableName() + " (" + columnNames + ") VALUES (" + placeholders + ")";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConnection();
ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
int index = 1;
for (String column : columns) {
Field field = entityClass.getDeclaredField(column);
field.setAccessible(true);
ps.setObject(index++, field.get(entity));
}
int affectedRows = ps.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Insert failed, no rows affected.");
}
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
return (ID) generatedKeys.getObject(1);
} else {
throw new SQLException("Insert failed, no ID obtained.");
}
}
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new SQLException("Save operation failed", e);
} finally {
closeResources(conn, ps, rs);
}
}
@Override
public void update(T entity) throws SQLException {
List<String> columns = getColumnNames();
String setClause = columns.stream()
.map(column -> column + " = ?")
.collect(Collectors.joining(", "));
String sql = "UPDATE " + getTableName() + " SET " + setClause +
" WHERE " + getIdColumnName() + " = ?";
Connection conn = null;
PreparedStatement ps = null;
try {
conn = getConnection();
ps = conn.prepareStatement(sql);
int index = 1;
for (String column : columns) {
Field field = entityClass.getDeclaredField(column);
field.setAccessible(true);
ps.setObject(index++, field.get(entity));
}
// 设置主键值
Field idField = entityClass.getDeclaredField(getIdColumnName());
idField.setAccessible(true);
ps.setObject(index, idField.get(entity));
ps.executeUpdate();
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new SQLException("Update operation failed", e);
} finally {
closeResources(conn, ps, null);
}
}
@Override
public void delete(ID id) throws SQLException {
String sql = "DELETE FROM " + getTableName() + " WHERE " + getIdColumnName() + " = ?";
executeUpdate(sql, id);
}
@Override
public List<T> findByCriteria(String whereClause, Object... params) throws SQLException {
String sql = "SELECT * FROM " + getTableName() + " WHERE " + whereClause;
return executeQuery(sql, params);
}
// === 辅助方法 ===
private List<T> executeQuery(String sql, Object... params) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<T> results = new ArrayList<>();
try {
conn = getConnection();
ps = conn.prepareStatement(sql);
setParameters(ps, params);
rs = ps.executeQuery();
while (rs.next()) {
results.add(mapResultSetToEntity(rs));
}
return results;
} finally {
closeResources(conn, ps, rs);
}
}
private int executeUpdate(String sql, Object... params) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = getConnection();
ps = conn.prepareStatement(sql);
setParameters(ps, params);
return ps.executeUpdate();
} finally {
closeResources(conn, ps, null);
}
}
private void setParameters(PreparedStatement ps, Object... params) throws SQLException {
if (params != null) {
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
}
}
}
```
#### 3. 连接池配置 (HikariCP)
```java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class DataSourceFactory {
private static HikariDataSource dataSource;
public static DataSource getDataSource() {
if (dataSource == null) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(20);
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
dataSource = new HikariDataSource(config);
}
return dataSource;
}
}
```
#### 4. 实体类与具体 DAO 实现
```java
// 实体类
public class User {
private Long id;
private String username;
private String email;
private Date createdAt;
// 构造器、getter/setter 省略...
}
// 具体 DAO 实现
public class UserDao extends AbstractJdbcDao<User, Long> {
public UserDao(DataSource dataSource) {
super(User.class, dataSource);
}
// 可覆盖默认表名
@Override
protected String getTableName() {
return "users";
}
// 自定义查询方法
public List<User> findByEmailDomain(String domain) throws SQLException {
return findByCriteria("email LIKE ?", "%@" + domain);
}
}
```
#### 5. 事务管理支持
```java
import java.sql.Connection;
import java.sql.SQLException;
public class TransactionManager {
private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
public static void beginTransaction() throws SQLException {
Connection conn = DataSourceFactory.getDataSource().getConnection();
conn.setAutoCommit(false);
threadLocal.set(conn);
}
public static void commit() throws SQLException {
Connection conn = threadLocal.get();
if (conn != null) {
conn.commit();
conn.close();
threadLocal.remove();
}
}
public static void rollback() {
Connection conn = threadLocal.get();
if (conn != null) {
try {
conn.rollback();
conn.close();
} catch (SQLException e) {
// 记录日志
} finally {
threadLocal.remove();
}
}
}
public static Connection getCurrentConnection() {
return threadLocal.get();
}
}
// 在 DAO 中支持事务
public class TransactionalDao<T, ID> extends AbstractJdbcDao<T, ID> {
public TransactionalDao(Class<T> entityClass, DataSource dataSource) {
super(entityClass, dataSource);
}
@Override
protected Connection getConnection() throws SQLException {
Connection conn = TransactionManager.getCurrentConnection();
if (conn != null) {
return conn; // 事务连接
}
return super.getConnection(); // 非事务连接
}
@Override
protected void closeResources(Connection conn, PreparedStatement ps, ResultSet rs) {
// 事务连接由事务管理器管理,不在此关闭
if (TransactionManager.getCurrentConnection() == null) {
super.closeResources(conn, ps, rs);
} else {
// 只关闭语句和结果集
try {
if (rs != null) rs.close();
if (ps != null) ps.close();
} catch (SQLException e) {
// 记录日志
}
}
}
}
```
#### 6. 使用示例
```java
public class UserService {
private final UserDao userDao;
public UserService() {
DataSource dataSource = DataSourceFactory.getDataSource();
this.userDao = new UserDao(dataSource);
}
public void createUser(User user) throws SQLException {
userDao.save(user);
}
public void updateUserEmail(Long userId, String newEmail) throws SQLException {
User user = userDao.findById(userId);
if (user != null) {
user.setEmail(newEmail);
userDao.update(user);
}
}
public void transferPoints(Long fromUserId, Long toUserId, int points) {
try {
TransactionManager.beginTransaction();
User fromUser = userDao.findById(fromUserId);
User toUser = userDao.findById(toUserId);
if (fromUser.getPoints() < points) {
throw new InsufficientPointsException();
}
fromUser.setPoints(fromUser.getPoints() - points);
toUser.setPoints(toUser.getPoints() + points);
userDao.update(fromUser);
userDao.update(toUser);
TransactionManager.commit();
} catch (Exception e) {
TransactionManager.rollback();
throw new ServiceException("Transaction failed", e);
}
}
}
```
### 关键设计说明
1. **泛型支持**:
- 通过反射自动映射结果集到实体对象
- 动态生成 SQL 语句
- 支持多种主键类型(Long、Integer、String 等)
2. **连接管理**:
- 使用 HikariCP 高性能连接池
- 资源自动关闭(try-with-resources 模式)
- 连接泄漏防护机制
3. **事务管理**:
- ThreadLocal 实现事务上下文
- 支持编程式事务
- 嵌套事务处理(需额外实现)
4. **扩展点**:
- 可覆盖表名映射逻辑
- 自定义字段映射策略
- 支持复杂查询条件
5. **性能优化**:
- 预编译语句缓存
- 批量操作支持(需扩展)
- 连接池参数调优
### 高级功能扩展建议
1. **分页查询支持**:
```java
public interface PageableDao<T, ID> extends BaseDao<T, ID> {
Page<T> findAll(Pageable pageable) throws SQLException;
}
```
2. **软删除实现**:
```java
@Override
public void delete(ID id) throws SQLException {
String sql = "UPDATE " + getTableName() + " SET deleted = 1 WHERE id = ?";
executeUpdate(sql, id);
}
```
3. **乐观锁支持**:
```java
@Override
public void update(T entity) throws SQLException {
// 添加版本检查
String sql = "UPDATE ... WHERE id = ? AND version = ?";
// 检查更新行数,处理并发冲突
}
```
4. **审计字段自动填充**:
```java
protected void preSave(T entity) {
if (entity instanceof Auditable) {
((Auditable) entity).setCreatedAt(new Date());
((Auditable) entity).setCreatedBy(currentUser());
}
}
```
阅读全文
相关推荐


















