{"record":{"id":"f1f3cc0fc16153a7","repo":"tursodatabase/turso","slug":"savepoints-are-not-supported-by-turso","errorCode":null,"errorMessage":"Savepoints are not supported by Turso","messagePattern":"Savepoints are not supported by Turso","errorType":"exception","errorClass":"SQLFeatureNotSupportedException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Connection.java","lineNumber":187,"sourceCode":"\n  @Override\n  public int getHoldability() throws SQLException {\n    connection.checkOpen();\n    return ResultSet.CLOSE_CURSORS_AT_COMMIT;\n  }\n\n  @Override\n  public void setHoldability(int holdability) throws SQLException {\n    connection.checkOpen();\n    if (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {\n      throw new SQLException(\"turso only supports CLOSE_CURSORS_AT_COMMIT\");\n    }\n  }\n\n  @Override\n  @SkipNullableCheck\n  public Savepoint setSavepoint() throws SQLException {\n    throw new SQLFeatureNotSupportedException(\"Savepoints are not supported by Turso\");\n  }\n\n  @Override\n  @SkipNullableCheck\n  public Savepoint setSavepoint(String name) throws SQLException {\n    throw new SQLFeatureNotSupportedException(\"Savepoints are not supported by Turso\");\n  }\n\n  @Override\n  public void rollback(Savepoint savepoint) throws SQLException {\n    throw new SQLFeatureNotSupportedException(\"Savepoints are not supported by Turso\");\n  }\n\n  @Override\n  public void releaseSavepoint(Savepoint savepoint) throws SQLException {\n    throw new SQLFeatureNotSupportedException(\"Savepoints are not supported by Turso\");\n  }\n","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Connection.java#L169-L205","documentation":"Turso's engine has no savepoint support, so Connection.setSavepoint() unconditionally throws SQLFeatureNotSupportedException. Savepoints would allow partial rollback inside a transaction, a feature SQLite-compatible engines exposed here do not provide through this driver.","triggerScenarios":"Direct call to conn.setSavepoint(); Spring @Transactional with propagation = Propagation.NESTED, which implements nesting via savepoints; test frameworks that create savepoints to roll back test data; generic transaction-management utilities that probe savepoint support by calling it.","commonSituations":"Spring/Hibernate applications using PROPAGATION_NESTED business methods; porting from PostgreSQL/Oracle where nested transactions via savepoints are routine; integration-test harnesses (e.g., @Transactional test rollback with nested transactional boundaries) that rely on savepoints.","solutions":["Replace Spring's Propagation.NESTED with Propagation.REQUIRES_NEW (independent transaction) or flatten the logic into one transaction.","Restructure code that needs partial rollback: validate before mutating, or sequence operations so a failure aborts the whole transaction, which is the SQLite model anyway.","Catch SQLFeatureNotSupportedException if a framework probes savepoint capability at startup, and configure the framework to treat savepoints as unavailable.","Remove direct setSavepoint calls; there is no driver flag to enable them."],"exampleFix":"// before (Spring)\n@Transactional(propagation = Propagation.NESTED) // internally calls setSavepoint()\npublic void updateInventory(Order o) { ... }\n\n// after\n@Transactional(propagation = Propagation.REQUIRES_NEW)\npublic void updateInventory(Order o) { ... }","handlingStrategy":"try-catch","validationCode":"if (conn.getMetaData().supportsSavepoints()) {\n    Savepoint sp = conn.setSavepoint();\n} else {\n    // no savepoints on this driver; use whole-transaction semantics\n}","typeGuard":null,"tryCatchPattern":"try {\n    sp = conn.setSavepoint();\n} catch (SQLFeatureNotSupportedException e) {\n    // savepoints unsupported: run the step as its own transaction or accept full rollback\n    sp = null;\n}","preventionTips":["Check supportsSavepoints() once at startup and disable savepoint code paths when false.","Avoid Spring Propagation.NESTED (savepoint-based); use REQUIRES_NEW or REQUIRED.","Design units of work so full rollback is acceptable, matching SQLite transaction semantics.","Do not port savepoint-based compensation logic verbatim from other databases."],"tags":["java","jdbc","savepoint","transactions","unsupported-feature","spring"],"backgroundTag":"savepoint-not-supported","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}