抽象类在java中不直接拼接sql,而是封装跨数据库共性逻辑(如字段转义、分页适配),通过模板方法定义流程、抽象方法交由子类实现方言差异,配合策略模式或框架协同实现多库兼容。

Java 中抽象类不能直接“拼接 SQL”,但可以在多数据库支持场景下,作为通用 SQL 构建逻辑的统一出口——关键不是写死 SQL,而是提取跨库共性行为(如字段名转义、分页语法适配、条件组装规范),用抽象类封装可复用骨架,再由子类按数据库方言定制实现。
抽象基类聚焦协议层,不碰具体 SQL 字符串
多数据库(MySQL/PostgreSQL/Oracle/SQL Server)的 SQL 差异大,硬拼字符串极易出错。抽象类应避开直接拼接,转而定义:
-
标准化接口方法:如
buildPaginationSql(String baseSql, Page page)、escapeIdentifier(String identifier)、buildInCondition(List<object> values)</object> -
受保护的模板方法:用
final封装主流程(如“先加 where 条件 → 再套分页 → 最后转义字段”),把差异点声明为abstract方法留给子类实现 -
统一参数契约:所有方法接收标准类型(
String、List>、Map<string object></string>),避免子类传入数据库特有对象(如PGobject)
子类按方言覆盖关键抽象方法
每个数据库对应一个继承自基类的具体实现类,只负责解决“怎么拼”的问题,不重复“拼什么”逻辑:
-
MySqlSqlBuilder extends BaseSqlBuilder:实现escapeIdentifier返回反引号包裹(`user_name`),buildPaginationSql用LIMIT ?, ? -
PostgreSqlBuilder extends BaseSqlBuilder:escapeIdentifier用双引号("user_name"),buildPaginationSql用OFFSET ? LIMIT ? -
OracleSqlBuilder extends BaseSqlBuilder:buildPaginationSql实现三层嵌套ROWNUM伪列分页
这样,业务代码只需面向 BaseSqlBuilder 编程,运行时注入对应方言实例,切换数据库只需替换 bean,无需改 SQL 组装逻辑。
配合数据库元信息做动态适配
纯靠继承有时不够灵活(比如同一应用需同时连 MySQL 和 PostgreSQL)。可在抽象基类中引入策略模式:
- 定义
DatabaseDialect枚举或接口,声明getLimitClause()、getEscapeChar()等能力 - 抽象类持有一个
DatabaseDialect实例,在构造时传入,内部方法通过委托调用 - 子类不再继承,而是作为工厂创建不同 dialect 的 builder 实例,更利于 Spring 容器管理
例如:new StandardSqlBuilder(DatabaseDialect.MYSQL) 或通过 @Qualifier("mysqlBuilder") 注入。
与 MyBatis-Plus 等框架协同而非替代
实际项目中,不建议从零手写 SQL 拼接器。抽象类更适合做“增强层”:
- 在 MyBatis-Plus 的
QueryWrapper基础上,抽象出MultiDbQuery类,统一处理跨库的orderBy字段转义、in参数长度分片(Oracle 限制 1000 个) - 为 JPA 的
CriteriaBuilder封装方言感知的buildCountQuery(),避免 HQL 在 Oracle 上报ORA-00923 - 将抽象类作为 DAO 层的父类,子类 DAO 持有 builder 实例,调用
builder.buildSelectSql(entityClass)获取基础语句,再交由框架执行
本质是把数据库差异收敛到有限几个点,让抽象类成为“协议翻译器”,而不是“SQL 生成器”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











