杰瑞科技汇

java 连接 sql server

目录

  1. 准备工作
    • 1 环境准备
    • 2 获取 SQL Server JDBC 驱动
    • 3 配置 SQL Server 服务器
  2. 核心代码实现
    • 1 添加 JDBC 驱动到项目
    • 2 基本连接代码 (JDBC 4.0+ 自动加载)
    • 3 完整的增删改查 示例
  3. 最佳实践
    • 1 使用 try-with-resources 管理资源
    • 2 使用连接池
    • 3 使用 PreparedStatement 防止 SQL 注入
  4. 常见问题与解决方案
    • 1 "No suitable driver found" 错误
    • 2 "The TCP/IP connection to the host has failed" 错误
    • 3 "Login failed for user 'sa'" 错误
    • 4 "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL)" 错误

准备工作

1 环境准备

  • Java 开发环境: 确保你已经安装了 JDK (Java Development Kit) 和一个 IDE (如 IntelliJ IDEA, Eclipse, 或 VS Code)。
  • SQL Server: 确保你的 SQL Server 实例正在运行,如果你没有安装,可以使用 Docker 快速启动一个,或者下载 SQL Server Developer Edition (免费)。

2 获取 SQL Server JDBC 驱动

微软提供了官方的 JDBC 驱动,你需要下载它并将其添加到你的 Java 项目中。

java 连接 sql server-图1
(图片来源网络,侵删)
  1. 下载地址: Microsoft JDBC Driver for SQL Server
  2. 选择版本: 根据你的 Java 版本和 SQL Server 版本选择合适的驱动,最新的驱动支持更广泛的 Java 和 SQL Server 版本。
  3. 下载文件: 下载后会得到一个 .zip 压缩包,解压后你会找到一个 mssql-jdbc-<version>.jar 文件,这就是你需要的 JDBC 驱动库。

3 配置 SQL Server 服务器

为了能让 Java 应用远程连接,你的 SQL Server 服务器需要进行一些基本配置。

  1. 启用 TCP/IP 协议:

    • 打开 SQL Server Configuration Manager
    • 在左侧导航栏中,展开 SQL Server 网络配置
    • 点击 SQLEXPRESS 的协议 (或你的实例名称)。
    • 在右侧,右键点击 TCP/IP,选择 启用
    • 重启 SQL Server 服务以使配置生效。
  2. 配置防火墙:

    • 确保运行 SQL Server 的机器的防火墙允许 TCP 端口 1433 (默认端口) 的入站连接。
  3. 创建测试用户和数据库 (推荐):

    java 连接 sql server-图2
    (图片来源网络,侵删)
    • 使用 SQL Server Management Studio (SSMS) 或其他工具连接到你的 SQL Server。
    • 执行以下 T-SQL 语句来创建一个测试数据库和一个有权限的用户:
      -- 创建一个名为 'JavaTestDB' 的数据库
      CREATE DATABASE JavaTestDB;

    -- 切换到新创建的数据库 USE JavaTestDB;

    -- 创建一个名为 'java_user' 的登录名,并设置密码 'YourStrongPassword123!' -- 注意:在生产环境中,请使用更复杂的密码 CREATE LOGIN java_user WITH PASSWORD = 'YourStrongPassword123!';

    -- 创建一个与登录名同名且映射到当前数据库的用户 CREATE USER java_user FOR LOGIN java_user;

    -- 授予该用户在当前数据库中所有对象的权限 GRANT ALL TO java_user;

    java 连接 sql server-图3
    (图片来源网络,侵删)

核心代码实现

1 添加 JDBC 驱动到项目

对于 Maven 项目: 在你的 pom.xml 文件中添加以下依赖,这是最推荐的方式,因为它会自动处理依赖关系。

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>11.2.1.jre17</version> <!-- 请根据你的 Java 版本选择合适的版本 -->
</dependency>

对于 Gradle 项目: 在你的 build.gradle 文件中添加:

implementation 'com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre17' // 请根据你的 Java 版本选择合适的版本

对于手动管理的项目:

  1. 将下载的 mssql-jdbc-<version>.jar 文件复制到你的项目的 lib 目录下。
  2. 在你的 IDE 中,右键点击该 JAR 文件,选择 "Add as Library..." 或类似选项,将其添加到项目的构建路径中。

2 基本连接代码

下面是建立连接的核心代码,URL 的格式非常重要。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class SqlServerConnector {
    // 数据库连接信息
    // 注意:SQL Server 和 Java 应用在同一台机器上,且使用 Windows 身份验证,则不需要用户名和密码
    private static final String DB_URL = "jdbc:sqlserver://localhost:1433;databaseName=JavaTestDB;encrypt=false;trustServerCertificate=true;";
    private static final String USER = "java_user";
    private static final String PASS = "YourStrongPassword123!";
    public static void main(String[] args) {
        // JDBC 4.0 (Java 6+) 之后,DriverManager 会自动加载类路径下的 JDBC 驱动
        // 所以不需要显式地 Class.forName(...)
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS)) {
            if (conn != null) {
                System.out.println("连接成功!");
                System.out.println("数据库版本: " + conn.getMetaData().getDatabaseProductVersion());
            }
        } catch (SQLException e) {
            System.err.println("连接失败!");
            e.printStackTrace();
        }
    }
}

URL 参数说明:

  • jdbc:sqlserver://: 固定协议头。
  • localhost:1433: SQL Server 的主机地址和端口号,如果你的服务器不在本机,请替换为实际的 IP 地址或域名。
  • databaseName=JavaTestDB: 要连接的数据库名称。
  • encrypt=false: 对于本地开发或非生产环境,可以禁用加密以简化连接,在生产环境中,应启用并正确配置 SSL。
  • trustServerCertificate=true: 在本地开发时,信任 SQL Server 提供的任何证书(即使它是自签名的)。在生产环境中,这非常不安全,应该设置为 false 并配置正确的信任存储。

3 完整的增删改查 示例

这个示例展示了如何执行查询、插入、更新和删除操作,并遵循了最佳实践。

import java.sql.*;
public class SqlServerCrudExample {
    private static final String DB_URL = "jdbc:sqlserver://localhost:1433;databaseName=JavaTestDB;encrypt=false;trustServerCertificate=true;";
    private static final String USER = "java_user";
    private static final String PASS = "YourStrongPassword123!";
    public static void main(String[] args) {
        // 创建表 (如果不存在)
        createTable();
        // 插入数据
        insertData("张三", 30);
        insertData("李四", 25);
        // 查询并显示所有数据
        selectAllData();
        // 更新数据
        updateAge("张三", 31);
        // 再次查询以验证更新
        System.out.println("\n更新后的数据:");
        selectAllData();
        // 删除数据
        deleteData("李四");
        // 最后一次查询
        System.out.println("\n删除后的数据:");
        selectAllData();
    }
    // 创建表
    private static void createTable() {
        String sql = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Employees' and xtype='U') CREATE TABLE Employees (id INT IDENTITY(1,1) PRIMARY KEY, name NVARCHAR(50), age INT)";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
            System.out.println("表 'Employees' 创建成功或已存在。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 插入数据
    private static void insertData(String name, int age) {
        // 使用 ? 占位符,防止 SQL 注入
        String sql = "INSERT INTO Employees (name, age) VALUES (?, ?)";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, name);
            pstmt.setInt(2, age);
            int affectedRows = pstmt.executeUpdate();
            System.out.println("插入了 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 查询所有数据
    private static void selectAllData() {
        String sql = "SELECT id, name, age FROM Employees";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            System.out.println("\n--- 员工列表 ---");
            while (rs.next()) {
                // 通过列名获取数据,更安全且可读性更好
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("ID: " + id + ", 姓名: " + name + ", 年龄: " + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 更新数据
    private static void updateAge(String name, int newAge) {
        String sql = "UPDATE Employees SET age = ? WHERE name = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, newAge);
            pstmt.setString(2, name);
            int affectedRows = pstmt.executeUpdate();
            System.out.println("\n更新了 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 删除数据
    private static void deleteData(String name) {
        String sql = "DELETE FROM Employees WHERE name = ?";
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, name);
            int affectedRows = pstmt.executeUpdate();
            System.out.println("\n删除了 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

最佳实践

1 使用 try-with-resources

从 Java 7 开始,推荐使用 try-with-resources 语句,它可以自动实现 AutoCloseable 接口的对象(如 Connection, Statement, ResultSet)在 try 块执行完毕后自动关闭,即使发生异常也是如此,这能有效防止资源泄漏。

如上面的 CRUD 示例所示,所有 JDBC 资源都使用了 try-with-resources

2 使用连接池

在真实的应用程序中,频繁地创建和销毁数据库连接是非常消耗资源的。连接池 应运而生,它预先创建一组数据库连接,并将它们缓存起来,当需要连接时,从池中获取一个,使用完毕后归还给池,而不是关闭。

  • 常用连接池: HikariCP (目前性能最好的连接池), Apache DBCP, C3P0。
  • 集成方式:
    • Spring Boot: 几乎是开箱即用,只需在 application.propertiesapplication.yml 中配置即可。
    • 手动集成: 将连接池库添加到项目中,然后通过其 API 获取连接。

HikariCP 示例 (Spring Boot application.properties):

# HikariCP 配置
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=JavaTestDB;encrypt=false;trustServerCertificate=true;
spring.datasource.username=java_user
spring.datasource.password=YourStrongPassword123!
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
# HikariCP 连接池特定配置
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000

3 使用 PreparedStatement

PreparedStatement 是预编译的 SQL 语句,它有两个主要好处:

  1. 防止 SQL 注入: 它会自动将输入参数进行转义,使得恶意代码无法作为 SQL 命令执行。
  2. 性能提升: 如果一条 SQL 语句需要被多次执行(只是参数不同),数据库可以只编译一次,多次执行,提高效率。

在执行 INSERT, UPDATE, DELETE 或带有参数的 SELECT 时,始终优先使用 PreparedStatement


常见问题与解决方案

1 "No suitable driver found for jdbc:sqlserver://..."

  • 原因: JDBC 驱动没有被加载到类路径中。
  • 解决方案:
    1. 确认你已将 mssql-jdbc.jar 文件添加到项目的构建路径中。
    2. 如果你使用 Maven 或 Gradle,检查 pom.xmlbuild.gradle 中的依赖是否正确,并执行 mvn clean installgradle build 重新下载依赖。
    3. 注意: 对于 JDBC 4.0+,通常不需要 Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 这行代码,如果加上这行代码能解决问题,说明你的类路径配置可能有问题,移除它,确保依赖正确是根本解决办法。

2 "The TCP/IP connection to the host has failed..."

  • 原因: Java 应用无法通过网络连接到 SQL Server 服务器。
  • 解决方案:
    1. 检查 SQL Server 服务: 确认 SQL Server 服务正在运行。
    2. 检查 TCP/IP 协议: 确认 SQL Server Configuration Manager 中的 TCP/IP 协议已启用。
    3. 检查防火墙: 确认运行 SQL Server 的机器的防火墙允许 1433 端口的入站连接,你可以暂时关闭防火墙进行测试。
    4. 检查连接字符串: 确认 IP 地址、端口和主机名是否正确。
    5. SQL Server Browser 服务: 如果你使用的是非默认端口或命名实例,需要确保 SQL Server Browser 服务正在运行。

3 "Login failed for user 'sa'."

  • 原因: SQL Server 拒绝了 sa 用户的登录请求。
  • 解决方案:
    1. 检查密码: 确认你提供的 sa 用户密码是正确的。
    2. 启用 'sa' 账户: 在 SSMS 中,以 Windows 身份验证登录,然后执行以下命令来启用并重置 sa 密码:
      ALTER LOGIN sa ENABLE;
      GO
      ALTER LOGIN sa WITH PASSWORD = 'YourNewStrongPassword!';
      GO
    3. 使用 Windows 身份验证: 如果可能,最好使用 Windows 身份验证,它更安全,连接字符串可以简化为 jdbc:sqlserver://localhost;databaseName=JavaTestDB;integratedSecurity=true;

4 "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL)..."

  • 原因: JDBC 驱动尝试与 SQL Server 建立加密连接,但配置不匹配或证书有问题。
  • 解决方案:
    1. 本地开发: 最简单的解决方法是在连接字符串中添加 encrypt=false;trustServerCertificate=true;,这会禁用加密并信任所有证书,仅适用于开发环境。
    2. 生产环境:
      • encrypt 设置为 true
      • trustServerCertificate 设置为 false
      • 你需要配置 Java 的信任存储库,将 SQL Server 的 CA 证书导入其中,这比较复杂,但能保证安全性。
分享:
扫描分享到社交APP
上一篇
下一篇