目录
-
第一步:准备工作
(图片来源网络,侵删)- 安装 SQL Server
- 安装 Java 开发环境
- 下载 SQL Server JDBC 驱动
- 准备数据库和表
-
第二步:使用 JDBC 驱动连接 (传统方法)
- 添加驱动到项目
- 编写 Java 连接代码
- 代码解析
- 完整示例
-
第三步:使用连接池 (推荐方法)
- 什么是连接池?
- 常用连接池库
- 使用 HikariCP 连接 SQL Server
- 连接池配置示例
-
第四步:现代方法:使用 JPA / Hibernate
- 简介
- 依赖配置
- 配置文件示例
- 简单的实体类和测试
-
第五步:常见问题与最佳实践
(图片来源网络,侵删)- 常见错误及解决方法
- 最佳实践总结
第一步:准备工作
在开始编码之前,请确保你已经完成了以下准备工作:
-
安装 SQL Server
- 确保你的机器上安装了一个可运行的 SQL Server 实例(可以是本地开发版、Express 版或 Docker 容器)。
- 记下你的服务器名称、端口号(默认为 1433)、用户名和密码。
-
安装 Java 开发环境
- 确保你已经安装了 JDK(建议 JDK 8 或更高版本)。
- 配置好
JAVA_HOME环境变量。 - 你可以使用任何 IDE,如 IntelliJ IDEA、Eclipse 或 VS Code。
-
下载 SQL Server JDBC 驱动
(图片来源网络,侵删)- 这是 Java 连接 SQL Server 的核心库。
- 访问微软官方下载页面:Microsoft JDBC Driver for SQL Server
- 下载与你的 JDK 版本和 SQL Server 版本相匹配的驱动包(通常是一个
.jar文件)。 - 注意:从 JDBC 4.0 开始,驱动支持自动加载,但显式加载仍然是好习惯。
-
准备数据库和表
- 在你的 SQL Server 实例中创建一个数据库和一个用于测试的表。
- 创建一个名为
TestDB的数据库,并在其中创建一个Employees表。
-- 创建数据库 CREATE DATABASE TestDB; GO -- 使用新数据库 USE TestDB; GO -- 创建员工表 CREATE TABLE Employees ( id INT PRIMARY KEY IDENTITY(1,1), name NVARCHAR(50) NOT NULL, department NVARCHAR(50), salary DECIMAL(10, 2) ); GO -- 插入一些测试数据 INSERT INTO Employees (name, department, salary) VALUES ('张三', '研发部', 8000.00), ('李四', '市场部', 7500.00), ('王五', '研发部', 9000.00); GO
第二步:使用 JDBC 驱动连接 (传统方法)
这是最基础、最直接的方式,适合学习和理解连接原理。
添加驱动到项目
你需要将下载的 JDBC 驱动 JAR 文件添加到你的 Java 项目的类路径中。
-
在 Maven 项目中:将 JAR 文件安装到本地 Maven 仓库,或在
pom.xml中直接指定,推荐使用 Maven,因为它可以自动管理依赖。<!-- 在 pom.xml 中添加依赖 --> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>11.2.1.jre8</version> <!-- 请使用最新版本 --> </dependency> -
在 Gradle 项目中:
// 在 build.gradle 中添加依赖 implementation 'com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre8' // 请使用最新版本
-
在普通 Java 项目中:将 JAR 文件复制到项目的
lib目录,并将其添加到 IDE 的库或构建路径中。
编写 Java 连接代码
下面是一个完整的 Java 类,演示了如何连接到 SQL Server,执行查询,并处理结果。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcSqlServerExample {
// 数据库连接信息
private static final String DB_URL = "jdbc:sqlserver://localhost:1433;databaseName=TestDB;encrypt=false;trustServerCertificate=true;";
// 如果你的 SQL Server 使用了 Windows 身份验证,用户名和密码可以省略或使用如下格式
// private static final String DB_URL = "jdbc:sqlserver://localhost:1433;databaseName=TestDB;integratedSecurity=true;encrypt=false;trustServerCertificate=true;";
private static final String USER = "sa"; // 你的数据库用户名
private static final String PASS = "your_password"; // 你的数据库密码
public static void main(String[] args) {
// try-with-resources 语句,确保资源被自动关闭
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, department, salary FROM Employees")) {
if (conn != null) {
System.out.println("成功连接到数据库!");
}
System.out.println("员工列表:");
System.out.println("---------------------------------");
// 遍历结果集
while (rs.next()) {
// 通过列名获取数据,更安全且可读性高
int id = rs.getInt("id");
String name = rs.getString("name");
String department = rs.getString("department");
double salary = rs.getDouble("salary");
System.out.printf("ID: %d, 姓名: %s, 部门: %s, 薪资: %.2f%n", id, name, department, salary);
}
} catch (SQLException e) {
System.err.println("数据库连接或查询失败!");
e.printStackTrace();
}
}
}
代码解析
DB_URL: 这是连接字符串,格式为jdbc:sqlserver://[server_name][:port];databaseName=[db_name];[other_properties]。encrypt=false;trustServerCertificate=true;: 这两个参数在本地开发时非常有用,它们可以避免 SSL/TLS 证书验证的麻烦,在生产环境中,你应该配置正确的 SSL 证书。
DriverManager.getConnection(): 这是建立连接的核心方法,它接收 URL、用户名和密码。try-with-resources: 这是一个 Java 7+ 的特性,它会自动在try代码块执行完毕后关闭Connection,Statement, 和ResultSet,防止资源泄漏。Statement: 用于执行静态 SQL 语句。ResultSet: 代表 SQL 查询返回的结果集,你可以通过next()方法遍历它,并用getXXX()方法获取数据。
第三步:使用连接池 (推荐方法)
在真实的应用程序中,频繁地创建和销毁数据库连接是非常消耗资源的。连接池应运而生,它预先创建一组数据库连接,并将其保存在池中,当需要连接时,从池中获取,用完后归还给池,而不是关闭。
什么是连接池?
连接池是一个管理数据库连接的缓存对象,它可以显著提高应用程序的性能和稳定性。
常用连接池库
- HikariCP: 目前性能最好的连接池,被誉为“连接池之王”,Spring Boot 2.x 默认使用它。
- Apache DBCP: 一个老牌的连接池实现。
- C3P0: 另一个流行的连接池,功能强大。
使用 HikariCP 连接 SQL Server
第一步:添加 HikariCP 依赖
<!-- 在 pom.xml 中添加 HikariCP 依赖 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version> <!-- 请使用最新版本 -->
</dependency>
第二步:编写连接池代码
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class HikariCPExample {
private static HikariDataSource dataSource;
// 静态代码块,在类加载时初始化连接池
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:sqlserver://localhost:1433;databaseName=TestDB;encrypt=false;trustServerCertificate=true;");
config.setUsername("sa");
config.setPassword("your_password");
// 连接池配置
config.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
config.setMaximumPoolSize(10); // 最大连接数
config.setMinimumIdle(5); // 最小空闲连接数
config.setConnectionTimeout(30000); // 连接超时时间 (ms)
config.setIdleTimeout(600000); // 空闲连接超时时间 (ms)
config.setMaxLifetime(1800000); // 连接最大存活时间 (ms)
config.setLeakDetectionThreshold(15000); // 连接泄漏检测时间 (ms)
dataSource = new HikariDataSource(config);
}
public static void main(String[] args) {
// 从连接池获取一个连接
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name, department FROM Employees WHERE department = '研发部'")) {
System.out.println("成功从连接池获取连接!");
System.out.println("研发部员工:");
System.out.println("---------------------------------");
while (rs.next()) {
String name = rs.getString("name");
String department = rs.getString("department");
System.out.printf("姓名: %s, 部门: %s%n", name, department);
}
} catch (Exception e) {
System.err.println("获取连接或查询失败!");
e.printStackTrace();
}
}
}
第四步:现代方法:使用 JPA / Hibernate
对于企业级应用,直接使用 JDBC 会写大量重复的样板代码。JPA (Java Persistence API) 是 Java EE 规范中用于对象/关系映射的标准,而 Hibernate 是 JPA 最流行的实现,它允许你用 Java 对象来操作数据库,而无需编写 SQL 语句。
简介
- ORM (Object-Relational Mapping): 将 Java 对象映射到数据库表。
- JPA: 规范/标准。
- Hibernate: JPA 规范的具体实现。
依赖配置
除了 JDBC 驱动和连接池,你还需要添加 JPA/Hibernate 的依赖。
<!-- 在 pom.xml 中添加 JPA / Hibernate 依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.15.Final</version> <!-- 请使用最新版本 -->
</dependency>
<!-- 连接池 (HikariCP) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
<!-- JDBC 驱动 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>11.2.1.jre8</version>
</dependency>
配置文件示例 (persistence.xml)
在 src/main/resources/META-INF/persistence.xml 文件中配置数据库连接和 Hibernate 设置。
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.Employee</class> <!-- 指定要管理的实体类 -->
<properties>
<!-- 数据库连接信息 (使用 HikariCP) -->
<property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://localhost:1433;databaseName=TestDB;encrypt=false;trustServerCertificate=true;"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value="your_password"/>
<property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<!-- Hibernate 特定属性 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- 自动更新表结构 -->
</properties>
</persistence-unit>
</persistence>
简单的实体类和测试
实体类 Employee.java
import javax.persistence.*;
@Entity
@Table(name = "Employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 50)
private String name;
@Column(length = 50)
private String department;
@Column(precision = 10, scale = 2)
private double salary;
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDepartment() { return department; }
public void setDepartment(String department) { this.department = department; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", department='" + department + '\'' +
", salary=" + salary +
'}';
}
}
测试类 HibernateExample.java
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.List;
public class HibernateExample {
public static void main(String[] args) {
// 创建 EntityManagerFactory,这会启动 Hibernate 并初始化连接池
EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit");
// 创建 EntityManager
EntityManager em = emf.createEntityManager();
try {
// 开始事务
em.getTransaction().begin();
// --- 查询示例 ---
List<Employee> employees = em.createQuery("SELECT e FROM Employee e WHERE e.department = '研发部'", Employee.class).getResultList();
System.out.println("研发部员工 (JPA/Hibernate):");
employees.forEach(System.out::println);
// --- 插入示例 ---
// Employee newEmployee = new Employee();
// newEmployee.setName("赵六");
// newEmployee.setDepartment("财务部");
// newEmployee.setSalary(6500.00);
// em.persist(newEmployee); // 将对象持久化
// 提交事务
em.getTransaction().commit();
} catch (Exception e) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback(); // 出错则回滚
}
e.printStackTrace();
} finally {
// 关闭资源
em.close();
emf.close(); // 关闭 EntityManagerFactory,销毁连接池
}
}
}
第五步:常见问题与最佳实践
常见错误及解决方法
-
com.microsoft.sqlserver.jdbc.SQLServerException: The TCP/IP connection to the host has failed.- 原因: SQL Server 服务未启动,或防火墙阻止了端口(1433)。
- 解决: 检查 SQL Server 服务状态,确保端口 1433 开放。
-
com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'sa'.- 原因: 用户名或密码错误,或者 SQL Server 未启用 "SQL Server 身份验证"。
- 解决: 检查密码,在 SQL Server Management Studio (SSMS) 中,右键点击服务器 -> "属性" -> "安全性",确保 "服务器身份验证" 设置为 "SQL Server 和 Windows 身份验证模式"。
-
java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver- 原因: JDBC 驱动 JAR 文件没有被正确添加到项目的类路径中。
- 解决: 检查 Maven/Gradle 依赖是否正确,或手动添加的 JAR 文件是否在
lib目录中并已添加到构建路径。
-
Connection is closed或Connection leak detected- 原因: 在使用完连接后没有正确关闭,尤其是在没有使用
try-with-resources的情况下。 - 解决: 始终使用
try-with-resources或在finally块中手动关闭Connection,Statement,ResultSet,使用连接池可以更好地检测泄漏。
- 原因: 在使用完连接后没有正确关闭,尤其是在没有使用
- 总是使用连接池:在生产环境中,绝对不要直接使用
DriverManager创建连接,HikariCP 是首选。 - 总是关闭资源:使用
try-with-resources或finally块确保Connection,Statement,ResultSet被正确关闭,防止资源泄漏。 - 使用
PreparedStatement:对于动态 SQL(带参数的查询),始终使用PreparedStatement而不是Statement,它可以防止 SQL 注入攻击,并且通常性能更好。 - 使用连接字符串中的列名:在
ResultSet中,使用rs.getString("column_name")而不是rs.getString(1),这样代码更健壮、可读性更高。 - 处理异常:妥善处理
SQLException,不要简单地printStackTrace()后就忽略它,至少要记录日志。 - 考虑使用 ORM 框架:对于复杂的应用程序,使用 JPA/Hibernate 等框架可以极大地提高开发效率和代码的可维护性。
- 配置 SSL/TLS:在生产环境中,务必在数据库连接字符串中启用
encrypt=true并配置正确的trustServerCertificate或提供服务器证书,以确保数据传输安全。
