【发布时间】:2018-06-15 05:07:50
【问题描述】:
我有一个连接到 Postgres 9.6 数据库的 Spring Boot webapp。
我使用 Spring 的JdbcTemplate 来执行 SQL 语句。
我数据库中的每个表都有 INSERT、CREATE 和 DELETE 语句的触发器。这些触发器将受影响的行复制到历史表中。
我希望触发器还保存进行更改的用户的应用程序用户 ID。
根据https://stackoverflow.com/a/13172964/2591231,我可以通过让应用程序在每个事务开始时将当前用户ID插入临时表并从临时表中读取触发器来实现我的目标。
在其他几个地方提到的类似方法正在执行:
SET LOCAL application_name = "my_application_user",然后在触发器内读取 application_name。同样,这必须在每笔交易开始时完成。
我正在寻找一种与业务代码正交的方法(我不希望每个 DAO 都显式设置用户 ID),以挂钩到每个事务的开始以运行特定的 SQL 语句 在同一事务中的任何其他语句之前。
我需要它同时适用于隐式事务(JdbcTemplate 的单个调用)和使用 Spring 的 @Transactional 注释以声明方式划分的事务。
【问题讨论】:
-
你想过使用 AOP 吗?还是 TransactionalEventListener?
-
TransactionalEventListener在事务开始时不通知。最早的事件(或TransactionPhase)是BEFORE_COMMIT,在我的情况下为时已晚,因为触发器已经执行。我正在考虑 AOP,即在 everyJdbcTemplate可以写入数据库的方法上放置一个切入点。在这些切入点上运行的建议将获取当前连接,将autoComit设置为false,运行我的特殊语句,然后仅之后继续使用joinPoint。但这看起来会很混乱,我将把它作为最后的手段。 -
这可以在数据源级别实现。只需要装饰返回的连接。一些数据源提供了这样做的方法。否则很容易覆盖 getConnection() 方法。可以使用 Spring DelegatingDataSource 来做到这一点。
-
你在重新发明轮子吗? javers.org
-
也许您可以通过扩展
DataSourceTransactionManager并覆盖正确的方法(doBegin、doCommit等)来使用自己的PlatformTransactionManager,但我不知道如何以及是否要正确管理临时表上的事务和 CRUD 操作
标签: java spring postgresql jdbc spring-jdbc