H2数据库报错JdbcSQLSyntaxErrorException: SPORTEVENT表不存在排查
问题根因
抛出Table "SPORTEVENT" not found错误是多个问题叠加导致的,和单独加DB_CLOSE_DELAY=-1参数没有直接关系:
- 核心问题:代码中从未执行过建表逻辑。H2内存数据库启动后默认是空库,不会自动创建业务表,现有代码只有插入数据的逻辑,没有创建
SPORTEVENT表的步骤,自然找不到对应表。 - 连接配置错误:JDBC URL拼接逻辑完全不符合H2规范。一方面实例化连接类时传入的
databaseName参数已经重复带了jdbc:h2:mem:前缀,最终拼接出的URL是无效的jdbc:h2:mem://localhost/jdbc:h2:mem:sports_betting;另一方面H2内存模式是JVM进程内数据库,不需要写//localhost/主机段,该格式是H2 TCP服务模式的写法。 - 附带逻辑错误:插入SQL的参数和字段不匹配。INSERT语句定义了6个字段,但代码中漏了
TITLE字段的赋值,参数序号错位,就算表存在也会抛出参数不匹配异常;同时new Date(2022-07-06)是语法错误,2022-07-06会被当成算术表达式计算为整数,生成的日期完全不符合预期。
修复步骤
按顺序修改以下代码即可解决问题:
- 修正数据库连接配置
首先修改DatabaseConnectionManager的构造方法,调整URL拼接规则,加上内存库持久化参数:
对应修改public DatabaseConnectionManager(String databaseName, String username,String password){ // H2内存库正确URL格式,不需要主机段,加上DB_CLOSE_DELAY=-1防止连接关闭后库被清空 this.url = "jdbc:h2:mem:"+databaseName+";DB_CLOSE_DELAY=-1"; this.properties = new Properties(); this.properties.setProperty("username",username); this.properties.setProperty("password",password); }JDBCExecutor中的连接实例化代码,不要重复传入JDBC前缀,只传库名即可:DatabaseConnectionManager databaseConnectionManager= new DatabaseConnectionManager("sports_betting","sa",""); - 补充建表逻辑
获取数据库连接后,在执行插入操作前先执行建表语句,避免表不存在:Connection connection = databaseConnectionManager.getConnection(); // 新增建表逻辑,表不存在时才创建 try(Statement stmt = connection.createStatement()){ stmt.execute("CREATE TABLE IF NOT EXISTS SPORTEVENT (" + "DTYPE VARCHAR(50) NOT NULL," + "ID INT PRIMARY KEY," + "START DATE," + "END DATE," + "TITLE VARCHAR(255)," + "RESULT_ID INT" + ")"); } - 修正插入逻辑和日期创建错误
首先修改SporteventDAO的create方法,补全缺失的TITLE参数赋值,修正参数序号:
然后修正@Override public FootballSportEvent create(FootballSportEvent dto) throws SQLException { try(PreparedStatement statement = this.connection.prepareStatement(INSERT);){ statement.setString(1,dto.getType()); statement.setInt(2,dto.getId()); statement.setDate(3, (Date) dto.getStart()); statement.setDate(4, (Date) dto.getEnd()); statement.setString(5, dto.getTitle()); // 补全之前缺失的TITLE字段赋值 statement.setInt(6, dto.getResultId()); // 修正参数序号,原代码错写为5 statement.execute(); }catch (SQLException e){ e.printStackTrace(); throw new RuntimeException(e); } return dto; }JDBCExecutor中的日期创建错误,给title字段赋值:// 用Date.valueOf生成合法的java.sql.Date对象,不要直接传算术表达式 Date start = Date.valueOf("2022-07-06"); Date end = Date.valueOf("2022-07-07"); footballSportEvent.setStart(start); footballSportEvent.setEnd(end); footballSportEvent.setResultId(2); footballSportEvent.setTitle("测试足球赛事"); // 给title字段赋值
补充:如果不想每次启动手动写建表逻辑,也可以在项目
resources目录下创建schema.sql文件,把建表语句写在文件中,H2启动时会自动执行该脚本完成表初始化。
内容的提问来源于stack exchange,提问作者Mat23
相关产品推荐
相关产品推荐

