java: DDD using sql server 2019 or Oracle21c
如何用工厂模式切换数据库系统
项目结构:
domain
--entities
----school.java
--repositories
----school.java
infrastructure
--database
-----duoraclehelper.java
--model
----school.java
--repositories
----Oracle
-------school.java
----Sqlserver
-------school.java
--common
----DatabaseType
--factories
----RepositoryFactory
--config
-----AppConfig
application
--server
-----school.java
presentation
--controllers
----school.java
--views
----school.java
main.java
只需改infrastructure,其他基本一样的。
/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1* # OS : window10* Datetime : 2025 - 2025/7/14 - 22:53* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : DatabaseType.java* explain : 学习 枚举**/
package infrastructure.common;/****/
public enum DatabaseType {ORACLE,SQL_SERVER,MYSQL,POSTGRESQL,SQLSERVER,SQLITE
}/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j* # OS : window10* Datetime : 2025 - 2025/7/14 - 23:06* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : AppConfig.java* explain : 学习 类**/package infrastructure.config;import infrastructure.common.DatabaseType;
import infrastructure.database.DatabaseConnectionFactory;
import infrastructure.factories.RepositoryFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;public class AppConfig {/****/private static final String CONFIG_FILE = "application.properties";private static Properties properties;static {loadConfig();initializeComponents();}private static void loadConfig() {properties = new Properties();try (InputStream is = AppConfig.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) {//AppConfig.class.getClassLoader() src 下if (is != null) {properties.load(is);} else {throw new IOException("无法加载配置文件: " + CONFIG_FILE);}} catch (IOException e) {System.err.println("加载配置文件失败: " + CONFIG_FILE);System.err.println("使用默认配置");throw new RuntimeException("加载配置失败", e);}}private static void initializeComponents() {String dbType = properties.getProperty("default.database.type", "SQL_SERVER");DatabaseType databaseType;// = DatabaseType.valueOf(dbType.toUpperCase());try {databaseType = DatabaseType.valueOf(dbType.toUpperCase());System.out.println(dbType);} catch (IllegalArgumentException e) {System.err.println("无效的数据库类型配置: " + dbType);System.err.println("使用默认值: SQL_SERVER");databaseType = DatabaseType.SQL_SERVER;}DatabaseConnectionFactory.initialize(databaseType);RepositoryFactory.initialize(databaseType);}public static String getProperty(String key) {return properties.getProperty(key);}
}/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j* # OS : window10* Datetime : 2025 - 2025/7/14 - 23:02* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : DatabaseConfigManager.java* explain : 学习 类**/package infrastructure.config;import infrastructure.database.DatabaseConnectionFactory;
import infrastructure.common.DatabaseType;
import infrastructure.factories.RepositoryFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;public class DatabaseConfigManager {private static final String CONFIG_FILE = "application.properties";private static Properties properties;private static final Map<DatabaseType, Map<String, String>> dbConfigs = new HashMap<>();private static DatabaseType activeDbType;static {loadConfig();initializeDbConfigs();// 设置默认数据库String defaultType = properties.getProperty("default.database.type", "SQL_SERVER");activeDbType = DatabaseType.valueOf(defaultType.toUpperCase());}private static void loadConfig() {properties = new Properties();String host = AppConfig.getProperty("sqlserver.host");String port = AppConfig.getProperty("sqlserver.port");String name = AppConfig.getProperty("sqlserver.name");System.out.println("host:"+host + ":" + port);try (InputStream is = DatabaseConfigManager.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) {if (is != null) {properties.load(is);} else {throw new IOException("无法加载配置文件: " + CONFIG_FILE);}} catch (IOException e) {throw new RuntimeException("加载配置失败", e);}}private static void initializeDbConfigs() {// 初始化 SQL Server 配置Map<String, String> sqlServerConfig = new HashMap<>();sqlServerConfig.put("host", properties.getProperty("sqlserver.host"));sqlServerConfig.put("port", properties.getProperty("sqlserver.port"));sqlServerConfig.put("name", properties.getProperty("sqlserver.name"));sqlServerConfig.put("user", properties.getProperty("sqlserver.user"));sqlServerConfig.put("password", properties.getProperty("sqlserver.password"));System.out.println(properties.getProperty("sqlserver.host"));dbConfigs.put(DatabaseType.SQL_SERVER, sqlServerConfig);// 初始化 Oracle 配置Map<String, String> oracleConfig = new HashMap<>();oracleConfig.put("host", properties.getProperty("oracle.host"));oracleConfig.put("port", properties.getProperty("oracle.port"));oracleConfig.put("sid", properties.getProperty("oracle.sid"));oracleConfig.put("serviceName", properties.getProperty("oracle.serviceName"));oracleConfig.put("user", properties.getProperty("oracle.user"));oracleConfig.put("password", properties.getProperty("oracle.password"));dbConfigs.put(DatabaseType.ORACLE, oracleConfig);}public static void setActiveDatabase(DatabaseType dbType) {activeDbType = dbType;// 重新初始化工厂和连接DatabaseConnectionFactory.initialize(activeDbType);RepositoryFactory.initialize(activeDbType);}public static Map<String, String> getActiveConfig() {return dbConfigs.get(activeDbType);}public static DatabaseType getActiveDbType() {return activeDbType;}}/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j* # OS : window10* Datetime : 2025 - 2025/7/14 - 23:04* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : DatabaseConnectionFactory.java* explain : 学习 类**/package infrastructure.database;import infrastructure.common.DatabaseType;
import infrastructure.config.AppConfig;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;public class DatabaseConnectionFactory {private static DatabaseType currentDbType;public static void initialize(DatabaseType dbType) {currentDbType = dbType;}/**** @return* @throws SQLException* @throws IOException*/public static Connection getConnection() throws SQLException, IOException {Properties props = new Properties();switch (currentDbType) {case ORACLE:String oracleUrl;//try {// 加载Oracle驱动//Class.forName("oracle.jdbc.OracleDriver");//} catch (ClassNotFoundException e) {//throw new SQLException("找不到Oracle JDBC驱动", e);//}if (AppConfig.getProperty("oracle.sid") != null) {oracleUrl = String.format("jdbc:oracle:thin:@//%s:%s/%s",AppConfig.getProperty("oracle.host"),AppConfig.getProperty("oracle.port"),AppConfig.getProperty("oracle.sid"));props.setProperty("user", AppConfig.getProperty("oracle.user"));props.setProperty("password", AppConfig.getProperty("oracle.password"));} else {oracleUrl = String.format("jdbc:oracle:thin:@//%s:%s/%s",AppConfig.getProperty("oracle.host"),AppConfig.getProperty("oracle.port"),AppConfig.getProperty("oracle.serviceName"));props.setProperty("user", AppConfig.getProperty("oracle.user"));props.setProperty("password", AppConfig.getProperty("oracle.password"));}return DriverManager.getConnection(oracleUrl, props);case SQL_SERVER://try {// 加载sqlserver驱动//Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");// } catch (ClassNotFoundException e) {// throw new SQLException("找不到sqlserver JDBC驱动", e);// }String sqlServerUrl = String.format("jdbc:sqlserver://%s:%s;databaseName=%s",AppConfig.getProperty("sqlserver.host"),AppConfig.getProperty("sqlserver.port"),AppConfig.getProperty("sqlserver.name"));String host = AppConfig.getProperty("sqlserver.host");String port = AppConfig.getProperty("sqlserver.port");String name = AppConfig.getProperty("sqlserver.name");String user=AppConfig.getProperty("sqlserver.user");String password=AppConfig.getProperty("sqlserver.password");// System.out.println("database host:"+host + ":" + port);//System.out.println("database user:"+user + ":" + password);props.setProperty("user", AppConfig.getProperty("sqlserver.user"));props.setProperty("password", AppConfig.getProperty("sqlserver.password"));System.out.println("database:"+sqlServerUrl);return DriverManager.getConnection(sqlServerUrl, user, password);default:throw new IllegalArgumentException("不支持的数据库类型");}}
}/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j* # OS : window10* Datetime : 2025 - 2025/7/18 - 20:09* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : OracleSchoolRepositoryImpl.java* explain : 学习 类**/package infrastructure.repositories.oracle;import domain.entities.School;
import domain.entities.QueryParams;
import domain.repositories.SchoolRepository;
import infrastructure.repositories.BaseRepository;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;public class OracleSchoolRepositoryImpl extends BaseRepository implements SchoolRepository {@Overridepublic List<School> findAll(int page, int pageSize) {System.out.println("开始分页查询,页码: " + page + ",每页大小: " + pageSize);List<School> schools = new ArrayList<>();String sql = "SELECT * FROM School ORDER BY SchoolId " +"OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";try (Connection conn = getConnection()) {System.out.println("成功获取数据库连接");try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, (page - 1) * pageSize);pstmt.setInt(2, pageSize);System.out.println("执行SQL: " + sql);System.out.println("参数1: " + (page - 1) * pageSize);System.out.println("参数2: " + pageSize);try (ResultSet rs = pstmt.executeQuery()) {while (rs.next()) {schools.add(mapToDomain(rs));}System.out.println("查询成功,返回 " + schools.size() + " 条记录");}}} catch (SQLException | IOException e) {System.err.println("数据库操作异常: " + e.getMessage());e.printStackTrace(); // 打印完整堆栈信息throw new RuntimeException("查询学校列表失败", e);}return schools;}@Overridepublic int countAll() {String sql = "SELECT COUNT(*) FROM School";try (Connection conn = getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql)) {if (rs.next()) {return rs.getInt(1);}} catch (SQLException | IOException e) {throw new RuntimeException("统计学校数量失败", e);}return 0;}@Overridepublic List<School> findByParams(QueryParams params) {List<School> schools = new ArrayList<>();String sql = "SELECT * FROM (" +" SELECT s.*, ROW_NUMBER() OVER (ORDER BY SchoolId) rn " +" FROM School s " +" WHERE 1=1 ";if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {sql += "AND (SchoolId LIKE ? OR SchoolName LIKE ?) ";}sql += ") WHERE rn BETWEEN ? AND ?";Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;try {conn = getConnection();pstmt = conn.prepareStatement(sql);int paramIndex = 1;if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {String searchTerm = "%" + params.getSearchTerm() + "%";pstmt.setString(paramIndex++, searchTerm);pstmt.setString(paramIndex++, searchTerm);}int startRow = (params.getPageNumber() - 1) * params.getPageSize() + 1;int endRow = params.getPageNumber() * params.getPageSize();pstmt.setInt(paramIndex++, startRow);pstmt.setInt(paramIndex, endRow);rs = pstmt.executeQuery();while (rs.next()) {schools.add(mapToDomain(rs));}} catch (SQLException | IOException e) {throw new RuntimeException("按条件查询学校失败", e);} finally {closeResources(conn, pstmt, rs);}return schools;}@Overridepublic int countByParams(QueryParams params) {StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM School WHERE 1=1 ");// 构建查询条件if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {sql.append("AND (SchoolId LIKE ? OR SchoolName LIKE ?)");}try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql.toString())) {int paramIndex = 1;// 设置查询参数if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {String searchTerm = "%" + params.getSearchTerm() + "%";pstmt.setString(paramIndex++, searchTerm);pstmt.setString(paramIndex, searchTerm);}try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {return rs.getInt(1);}}} catch (SQLException | IOException e) {throw new RuntimeException("统计符合条件的学校数量失败", e);}return 0;}@Overridepublic School findById(String schoolId) {String sql = "SELECT * FROM School WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, schoolId);try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {return mapToDomain(rs);}}} catch (SQLException | IOException e) {throw new RuntimeException("查找学校失败", e);}return null;}@Overridepublic void save(School school) {// 检查是插入还是更新if (findById(school.getSchoolId()) == null) {insertSchool(school);} else {updateSchool(school);}}private void insertSchool(School school) {String sql = "INSERT INTO School (SchoolId, SchoolName, SchoolTelNo) VALUES (?, ?, ?)";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, school.getSchoolId());pstmt.setString(2, school.getSchoolName());pstmt.setString(3, school.getSchoolTelNo());pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("添加学校失败", e);}}private void updateSchool(School school) {String sql = "UPDATE School SET SchoolName = ?, SchoolTelNo = ? WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, school.getSchoolName());pstmt.setString(2, school.getSchoolTelNo());pstmt.setString(3, school.getSchoolId());pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("更新学校失败", e);}}@Overridepublic void delete(String schoolId) {String sql = "DELETE FROM School WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, schoolId);pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("删除学校失败", e);}}private School mapToDomain(ResultSet rs) throws SQLException {return new School(rs.getString("SchoolId"),rs.getString("SchoolName"),rs.getString("SchoolTelNo"));}}/*** encoding: utf-8* 版权所有 2025 ©涂聚文有限公司 ®* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎* 描述:* Author : geovindu,Geovin Du 涂聚文.* IDE : IntelliJ IDEA 2024.3.6 Java 17* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j* # OS : window10* Datetime : 2025 - 2025/7/18 - 19:57* User : geovindu* Product : IntelliJ IDEA* Project : DDDdemo* File : SqlServerSchoolRepositoryImpl.java* explain : 学习 类**/package infrastructure.repositories.sqlserver;import domain.entities.School;
import domain.entities.QueryParams;
import domain.repositories.SchoolRepository;
import infrastructure.repositories.BaseRepository;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;public class SqlServerSchoolRepositoryImpl extends BaseRepository implements SchoolRepository {@Overridepublic List<School> findAll(int page, int pageSize) {List<School> schools = new ArrayList<>();// SQL Server 2012+ 分页语法String sql = "SELECT * FROM School " +"ORDER BY SchoolId " +"OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, (page - 1) * pageSize);pstmt.setInt(2, pageSize);try (ResultSet rs = pstmt.executeQuery()) {while (rs.next()) {schools.add(mapToDomain(rs));}}} catch (SQLException | IOException e) {throw new RuntimeException("查询学校列表失败", e);}return schools;}@Overridepublic int countAll() {String sql = "SELECT COUNT(*) FROM School";try (Connection conn = getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql)) {if (rs.next()) {return rs.getInt(1);}} catch (SQLException | IOException e) {throw new RuntimeException("统计学校数量失败", e);}return 0;}@Overridepublic List<School> findByParams(QueryParams params) {List<School> schools = new ArrayList<>();StringBuilder sql = new StringBuilder("SELECT * FROM School WHERE 1=1 ");if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {sql.append("AND (SchoolId LIKE ? OR SchoolName LIKE ?) ");}sql.append("ORDER BY SchoolId OFFSET ? ROWS FETCH NEXT ? ROWS ONLY");Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;try {conn = getConnection();pstmt = conn.prepareStatement(sql.toString());int paramIndex = 1;if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {String searchTerm = "%" + params.getSearchTerm() + "%";pstmt.setString(paramIndex++, searchTerm);pstmt.setString(paramIndex++, searchTerm);}pstmt.setInt(paramIndex++, (params.getPageNumber() - 1) * params.getPageSize());pstmt.setInt(paramIndex, params.getPageSize());rs = pstmt.executeQuery();while (rs.next()) {schools.add(mapToDomain(rs));}} catch (SQLException | IOException e) {throw new RuntimeException("按条件查询学校失败", e);} finally {closeResources(conn, pstmt, rs);}return schools;}@Overridepublic int countByParams(QueryParams params) {StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM School WHERE 1=1 ");// 构建查询条件if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {sql.append("AND (SchoolId LIKE ? OR SchoolName LIKE ?)");}try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql.toString())) {int paramIndex = 1;// 设置查询参数if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {String searchTerm = "%" + params.getSearchTerm() + "%";pstmt.setString(paramIndex++, searchTerm);pstmt.setString(paramIndex, searchTerm);}try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {return rs.getInt(1);}}} catch (SQLException | IOException e) {throw new RuntimeException("统计符合条件的学校数量失败", e);}return 0;}@Overridepublic School findById(String schoolId) {String sql = "SELECT * FROM School WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, schoolId);try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {return mapToDomain(rs);}}} catch (SQLException | IOException e) {throw new RuntimeException("查找学校失败", e);}return null;}@Overridepublic void save(School school) {// 检查是插入还是更新if (findById(school.getSchoolId()) == null) {insertSchool(school);} else {updateSchool(school);}}private void insertSchool(School school) {String sql = "INSERT INTO School (SchoolId, SchoolName, SchoolTelNo) VALUES (?, ?, ?)";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, school.getSchoolId());pstmt.setString(2, school.getSchoolName());pstmt.setString(3, school.getSchoolTelNo());pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("添加学校失败", e);}}private void updateSchool(School school) {String sql = "UPDATE School SET SchoolName = ?, SchoolTelNo = ? WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, school.getSchoolName());pstmt.setString(2, school.getSchoolTelNo());pstmt.setString(3, school.getSchoolId());pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("更新学校失败", e);}}@Overridepublic void delete(String schoolId) {String sql = "DELETE FROM School WHERE SchoolId = ?";try (Connection conn = getConnection();PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, schoolId);pstmt.executeUpdate();} catch (SQLException | IOException e) {throw new RuntimeException("删除学校失败", e);}}private School mapToDomain(ResultSet rs) throws SQLException {return new School(rs.getString("SchoolId"),rs.getString("SchoolName"),rs.getString("SchoolTelNo"));}}