
最近帮一位刚转后端的朋友从零配环境他卡在了特别基础的地方JDK装好了但javac用不了PostgreSQL 装完连不上最后项目连数据库报了一堆错。这种问题对老手来说就是几分钟的事但对零基础的人来说每一步都可能劝退。这篇就是按照我平时带新人的思路把 JDK21 PostgreSQL Java 后端项目这条链路完整走一遍从版本选择、安装配置、数据库初始化到真正写接口跑起来全部覆盖。适合完全没接触过后端开发、想从零搭起自己第一个项目的朋友也适合装完环境但总在某个环节卡住的人对照排查。我尽量把每个操作背后的原因讲清楚而不只是给命令这样你遇到意外情况时知道从哪里下手。1. 先从版本选型说起JDK21和PostgreSQL到底装哪个很多零基础的朋友一上来就问我该下哪个版本这个纠结很正常。版本选错了后面跟着教程走就会发现命令对不上、依赖报错。我直接说说当前实践里的选择逻辑。1.1 JDK21为什么零基础直接选它而不是17或25JDK21是Java的长期支持版本LTS这意味着甲骨文会持续提供多年免费更新和修复企业生产环境更愿意用这种版本。上一个LTS是JDK17目前在存量项目里还很多但新项目用21已经非常普遍Spring Boot 3.x、主流框架都主动适配了21。至于更新但非LTS的JDK25之类普通学习者没必要追企业也不会贸然升级。还有个实际原因你在社区里搜JDK21安装步骤JDK21 Linux安装包下载能找到大量踩坑记录和现成方案遇到问题容易定位。跟着一个冷门版本折腾出了问题连排查案例都很难找。如果你未来要投简历、面试现在不少公司的笔试环境也是21。从零基础直接学21知识不会白学语法与老版本差异不大反而是新特性比如虚拟线程会让你站得比只会老版本的人靠前一点。1.2 PostgreSQL16、17还是便携版PostgreSQL的版本迭代比较快目前16是社区公认最稳的主流版本教程数量最多17属于较新版本功能有更新但有些运维工具、依赖库对新版本的支持可能滞后一点。对于学习阶段我建议装16稳妥最重要。至于postgresql 16便携版它指的是免安装的zip二进制包解压就能用不需要系统服务适合临时体验或在受限环境使用。便携版不是不能用但对零基础不太友好——它需要手动初始化数据目录、手动启动服务、手动配置环境变量任何一步出错你都很难分清是系统问题还是配置问题。而 Windows 安装包EDB Installer自带图形化向导和服务注册跟着点下一步就能把数据库跑起来。新手阶段我强烈推荐用安装包方式等你明白了服务、端口、数据目录这些概念再回去玩便携版会轻松很多。2. 两台电脑的安装实录Windows和Linux服务器都要会配环境搭建这部分我拆成 Windows 本机和 Linux 服务器两个场景。日常学习主要在Windows但很多人的项目最终要部署到Linux上热搜里也有linux新安装的服务器如何设置jdk21环境变量说明这是后端入职后的第一道坎。两边都要会。2.1 Windows端从下载到 javac -version 第一次跑通下载JDK21时优先去官方网站或国内镜像。安装时建议装到一个简单路径比如D:\Java\jdk-21装完后系统可能会自动配置部分环境变量但手动设置一遍能帮你真正理解背后的机制也能避免多版本冲突。具体操作是打开系统属性 → 环境变量在系统变量里新增JAVA_HOMED:\Java\jdk-21Path 中追加一条%JAVA_HOME%\bin然后重新打开一个cmd窗口分别执行java -version javac -version如果java -version正常但javac -version提示不是内部或外部命令十有八九是Path里只配了Java安装目录本身没配到bin这一层。因为java.exe和javac.exe都在%JAVA_HOME%\bin里Path必须精确到bin目录才能被系统找到。还有一个常见坑你电脑上装了不止一个JDK比如旧项目要求JDK8新项目要求JDK21。这时不要删掉旧的你的JAVA_HOME指向谁命令行里就是谁。如果切换后 java -version 没变请检查Path里是否混入了C:\Program Files\Common Files\Oracle\Java\javapath这种优先级更高的条目把它移到末尾或直接移除多版本切换才能干净。2.2 Linux端服务器上JDK21环境变量到底怎么配Linux服务器上一般有两种安装JDK的方式用包管理器apt/dnf/yum安装或者下载tar.gz解压安装。生产服务器我习惯用tar.gz方式因为版本可控、卸载干净。以最常见的 CentOS 7 为例先下载linux x64的tar.gz安装包然后在/usr/local下解压tar -zxvf jdk-21_linux-x64_bin.tar.gz -C /usr/local mv /usr/local/jdk-21 /usr/local/java接着编辑/etc/profile在文件末尾追加export JAVA_HOME/usr/local/java export PATH$JAVA_HOME/bin:$PATH执行source /etc/profile让配置立即生效然后验证java -version javac -version这里有个注意事项有些系统自带OpenJDK导致java -version显示的是旧版本但echo $JAVA_HOME却指向了你的新路径。原因可能是旧JDK的路径提前写在了/etc/profile.d/下的某个脚本里。遇到这种情况需要找到并注释掉那个脚本中的相关行或者在/etc/profile末尾用 export 强制覆盖PATH顺序。配置完JDK可以顺手确认which java指向的是/usr/local/java/bin/java这样部署Spring Boot的java -jar命令才能用对版本。2.3 PostgreSQL安装最容易翻车的服务启动问题先讲Windows下的安装包方式。运行安装向导时有几个界面值得留意安装组件默认全选即可包括 pgAdmin 和 Stack Builder。Stack Builder用处不大可以取消。数据目录默认C:\Program Files\PostgreSQL\16\data建议改到非系统盘。超级用户密码这是 postgres 用户的密码务必记牢后续所有连接都绕不开它。端口默认5432除非被占用否则不要改。Locale强烈建议选择UTF-8否则后面建中文数据容易乱码。安装完成后PostgreSQL会注册为Windows系统服务默认自动启动。很多人在这时遇到服务启动失败最常见的几个原因按概率排序是端口被占用另一个PostgreSQL实例或者其他程序占用了5432。用netstat -ano | findstr 5432查一下就能看到占用进程。数据目录权限不足安装过程中如果路径包含中文或空格或者Windows账户权限受限服务启动时无法读写数据目录。杀毒软件拦截数据库服务监听端口、写文件时某些杀毒软件会拦截导致启动后立刻退出。排查服务问题打开服务管理窗口找到postgresql-x64-16双击看启动参数和错误信息Windows事件查看器里也有详细日志。这是最快定位手段。再讲Linux以 CentOS 7 为例。如果从官方yum仓库装先装仓库源再执行yum install -y postgresql-server postgresql-contrib /usr/pgsql-16/bin/postgresql-16-setup initdb systemctl start postgresql-16 systemctl enable postgresql-16CentOS 7 上最常见的安装后问题是initdb没执行服务直接启动会失败提示找不到数据目录。记得在服务启动前执行初始化命令。初始化完成后默认会创建一个postgres系统用户数据库超级用户也是postgres。Ubuntu方式不同但核心逻辑一致安装包 → 初始化数据目录有些发行版自动完成→ 启动服务 → 设置密码。3. 数据库侧的准备工作建库、建用户、看懂连接参数服务启动成功只是第一步你还需要亲手建一个业务数据库和对应账号。这块是数据库侧面向Java项目的接待前台搞不清楚后面谁都连不上。3.1 用psql初始化业务库和业务账号先用超级用户登录默认的postgres库psql -U postgres -h localhost -p 5432输入安装时设置的密码后执行以下SQLCREATE USER app_user WITH PASSWORD app_pass_2024; CREATE DATABASE app_db OWNER app_user;然后把库的权限给业务用户GRANT ALL PRIVILEGES ON DATABASE app_db TO app_user;这里给零基础解释一下为什么强调不要拿postgres超级用户直接去连业务库。超级用户在数据库里权限太大可以删库、改全局配置。项目代码一旦被注入或误操作损失不可控。用专门的应用账号只给最小权限这是从学习阶段就要养成的习惯。万一你真在开发时把表误删了损失也限定在单个库内不至于把整个实例搞崩。建好之后用新账号验证一下能否连上psql -U app_user -h localhost -p 5432 -d app_db3.2 JDBC URL解析后端连库的五要素Java程序连数据库靠的是一串连接字符串也叫 JDBC URL。最常见的PostgreSQL写法长这样jdbc:postgresql://localhost:5432/app_db这串东西拆开看就是五要素部分作用常见问题jdbc:postgresql://固定协议头拼错就报 driver 错误localhost数据库所在主机写成别的IP连不上5432端口数据库换过端口这里要同步改app_db数据库名大小写敏感写错直接database not existusername/password账号密码不写在URL里通常放配置认证失败九成是这里我给你个更完整的连接签名示例Java代码里的参数通常这样填String url jdbc:postgresql://localhost:5432/app_db; String user app_user; String password app_pass_2024;有的教程会教你加?sslfalsestringtypeunspecified之类参数学习阶段先不用管等你在真实环境遇到加密连接需求再回来研究。4. 第一个Java后端工程从JDBC裸连到Spring Boot接口环境都通了接下来是重头戏让Java代码真正读写PostgreSQL。我会先展示最朴素的JDBC写法因为它能让你直观理解驱动加载 → 建立连接 → 执行SQL → 处理结果这个完整链路然后马上切换到Spring Boot方案因为这才是日常开发真正在用的东西。4.1 最小可跑的JDBC写法理解底层在发生什么用Maven创建一个空项目在pom.xml里加驱动依赖dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId version42.7.3/version /dependency然后写一个最简查询import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class PgTest { public static void main(String[] args) throws Exception { String url jdbc:postgresql://localhost:5432/app_db; String user app_user; String password app_pass_2024; Connection conn DriverManager.getConnection(url, user, password); Statement st conn.createStatement(); ResultSet rs st.executeQuery(SELECT version()); if (rs.next()) { System.out.println(rs.getString(1)); } rs.close(); st.close(); conn.close(); } }注意几个细节。第一新版驱动可以不用手动Class.forName(org.postgresql.Driver)但如果你在部分环境里遇到No suitable driver found手动加上这一行会有帮助。第二JDBC代码里的conn、st、rs用完后必须关闭实际项目里应该用 try-with-resources。第三PostgreSQL驱动版本号42.x对应JDK8及以上和JDK21兼容没问题但老版本驱动比如9.x连接新版PostgreSQL时认证协议可能不匹配表现为password authentication failed这跟你的密码无关纯粹是驱动太老不认新认证方式。遇到这种报错优先把驱动升级到最新。4.2 生产级路径Spring Boot 3 数据源配置 一个REST接口JDBC裸写帮你理解原理但真实后端项目不可能用裸JDBC管理几十张表。现在切换到Spring Boot——它是Java后端事实上的标准框架也是热搜里spring boot 3出现频率高的原因。用Spring Initializr生成项目时选择Java版本21Spring Boot版本3.2.x 或更新稳定版依赖Spring Web、Spring Data JDBC或者Spring Data JPA、PostgreSQL Driver生成后打开src/main/resources/application.yml配置数据源spring: datasource: url: jdbc:postgresql://localhost:5432/app_db username: app_user password: app_pass_2024 driver-class-name: org.postgresql.Driver然后写一个最简单的接口直接查数据库import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.jdbc.core.JdbcTemplate; RestController public class HelloController { private final JdbcTemplate jdbcTemplate; public HelloController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate jdbcTemplate; } GetMapping(/ping) public String ping() { Integer one jdbcTemplate.queryForObject(SELECT 1, Integer.class); return db ok: one; } }这里Spring Boot自动帮你完成了数据源创建 → 连接池管理 → JdbcTemplate注入这些工作。把应用跑起来后浏览器访问http://localhost:8080/ping如果返回db ok: 1说明Java项目到PostgreSQL整条链路已经打通。我建议你先跑通这样一个最小闭环再去理解Controller、Service、Repository分层。后端开发本质上没有玄学就是把收到的请求转成SQL把数据库结果转成JSON还给前端。先看见这条主链路跑通后面的框架学习才有抓手。4.3 把项目跑起来验证从IDEA到命令行这里有个零基础常犯的错在IDEA里点了运行浏览器却访问不到。优先确认应用日志里出现了Tomcat started on port 8080这行日志才是真正的启动成功信号而不仅仅是控制台没报错。如果8080被占用Spring Boot会启动失败日志会明确写Port 8080 was already in use。启动成功后用命令行验证更直接curl http://localhost:8080/ping看到返回内容就说明接口对外可用了。如果日志正常但curl超时检查防火墙是否拦截了8080端口Windows和Linux都有这个问题。5. 零基础翻车清单连接被拒、密码失败、中文乱码的完整排查链路到这一步环境能跑了但真实开发中你一定会遇到各种报错。我把零基础最容易撞上的几种问题整理成完整的排查链路你照着这条思路定位会比满世界搜报错高效得多。5.1 数据库连接被拒与端口占用的定位流程报错常见字符串是Connection refused或Connection timed out。前者表示目标主机拒绝了连接请求通常意味着数据库服务没监听、防火墙拦截或端口号写错后者多半是网络不通或数据库在另一台机器上。完整定位顺序是确认服务进程在跑。Windows看服务窗口里的postgresql-x64-16状态Linux执行systemctl status postgresql-16。确认端口在监听。Windows执行netstat -ano | findstr 5432Linux执行ss -lntp | grep 5432。确认连接地址没有写错。本地连接写localhost或127.0.0.1远程连接要写数据库服务器IP并确认数据库配置里允许远程访问——PostgreSQL默认只监听本机这个后面细说。确认Java项目日志里的报错时间点和MySQL不同PostgreSQL会在日志里输出拒绝原因默认路径在数据目录下的log/文件夹。我把端口占用时的检查命令整理成一个小表操作系统查看5432端口占用查看8080端口占用Windowsnetstat -ano | findstr 5432netstat -ano | findstr 8080Linuxss -lntp | grep 5432ss -lntp | grep 8080查到占用进程号后任务管理器或kill即可但要注意确认是不是真的可以杀掉——如果是另一个数据库实例杀了会影响其他服务。5.2 认证失败的三种原因与pg_hba.conf的关系password authentication failed for user xxx是所有新手都会撞到的报错但它未必是密码错。第一种确实是密码错。密码里如果有、#、$这类特殊字符写在application.yml里要注意转义。更推荐的做法是把密码放到环境变量里不在代码里硬编码。第二种认证方式不匹配。PostgreSQL的pg_hba.conf文件控制哪些IP、哪些用户可以什么方式登录。安装时如果选择了scram-sha-256而驱动版本太老只认md5就会报认证失败。解决办法是升级JDBC驱动或者把pg_hba.conf里的认证方式统一。第三种用户或数据库不存在。报错有时候是database app_db does not exist那跟密码无关纯粹是把库名写错了。PostgreSQL对大小写敏感App_db和app_db是两个东西。这个文件位置在WindowsC:\Program Files\PostgreSQL\16\data\pg_hba.confLinux/var/lib/pgsql/16/data/pg_hba.conf修改后需要重启服务才生效。在开发环境图省事把它们全改成trust是可以的但生产环境千万别这么干。5.3 中文编码与页面乱码的处理零基础项目最容易碰到的乱码场景是往数据库里插入中文读出来是????。这通常是客户端编码和数据库编码不一致造成的。安装PostgreSQL时已经选过UTF-8但你可以在psql里确认SHOW server_encoding;正常应该返回UTF8。如果返回的是SQL_ASCII或GBK那建库时就要指定编码CREATE DATABASE app_db WITH ENCODING UTF8 LC_COLLATE zh_CN.UTF-8;另外Spring Boot连接数据库时JDBC URL可以显式指定客户端编码jdbc:postgresql://localhost:5432/app_db?characterEncodingUTF-8不过PostgreSQL驱动8.0之后默认就是UTF-8这套参数主要用于排查不一定需要每次都写。6. 项目做出来后怎么往前后端分离靠拢很多零基础朋友学的是Java后端但实际岗位要求里常常出现前后端分离项目实战vue3访问后端。我在最后给出一条从单体命令行程序往前端分离工程演进的路径。Spring Boot默认的监听地址是localhost也就是只有本机能访问。当你用Vue开发服务器或者手机真机调试时会发现接口访问不到。这时要把监听地址改成0.0.0.0在application.yml里加server: address: 0.0.0.0 port: 8080改成0.0.0.0后局域网内的其他设备就能通过服务器IP访问了。注意这里的防火墙要放行8080端口。前后端分离还有一个经典问题跨域。前端在http://localhost:5173后端在http://localhost:8080浏览器会拦截跨域请求。在后端写一个配置类允许前端来源是常见解法import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(http://localhost:5173) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS); } }到这一步你手里的工程已经从黑窗口里跑jar包变成了能被前端页面调用的真正后端服务。后面再学接口设计规范、统一异常处理、权限校验就是在这个骨架上逐步加肉了。带过的人多了之后我有个体会零基础入门最忌讳的是同时开太多战线今天学两句Java语法明天装个数据库后天又跑去折腾Linux。不如就照着装环境 → 建库 → 跑通一个接口 → 前后端联调这条主线一周内把一个最小闭环彻底跑通之后再往深处挖。过程中所有报错都是正常的按着看服务 → 看端口 → 看日志 → 看配置的顺序排查大部分问题都能自己定位。剩下的就是多写、多踩坑、多把报错完整读一遍——相信我后端这条路上九成的问题你在网上都能搜到答案。