Aar*_*lla 5 java connection spring jdbc spring-transactions
想象一下这段代码:
foo() {
Connection conn = ...;
}
Run Code Online (Sandbox Code Playgroud)
foo()
已从具有注释的方法调用@Transactional
.如何获取当前的JDBC连接?请注意,foo()
它位于bean中(因此它可以包含@Autowired
字段)但foo()
不能包含参数(因此我无法从某处传递连接).
[编辑]我正在使用需要数据源或连接的jOOQ.我的问题:我不知道配置了哪个事务管理器.它可能是任何东西; Java EE,基于DataSource,通过JNDI获取数据源.我的代码不是应用程序,它是一个库.我需要吞下别人放在盘子里的东西.同样,我不能请求Hibernate会话工厂,因为使用我的应用程序可能不会使用Hibernate.
但我知道其他代码,如Spring Hibernate集成,不知何故可以从事务管理器获取当前连接.我的意思是,Hibernate不支持Spring的事务管理器,因此粘合代码必须使Spring API适应Hibernate所期望的.我需要做同样的事情,但我无法弄清楚它是如何工作的.
[EDIT2]我知道有一个活动事务(即Spring在某个地方有一个Connection实例,或者至少有一个事务管理器可以创建一个),但我的方法不是@Transactional.我需要调用一个构造函数java.sql.Connection
作为参数.我该怎么办?
(完全基于评论线程重写;不知道为什么我的原始答案专注于Hibernate,除了那是我现在正在使用的)
事务管理器与数据源完全正交.一些事务管理器直接与数据源交互,一些通过中间层(例如,Hibernate)交互,一些交互管理器通过容器提供的服务(例如,JTA)进行交互.
当你将方法标记为时@Transactional
,所有这意味着Spring将在加载bean时生成代理,并且该代理将被传递给任何其他想要使用bean的类.当调用代理的方法时,它(代理)要求事务管理器为其提供未完成的事务或创建新的事务.然后它调用你的实际bean方法.当bean方法返回时,代理再次与事务管理器交互,要么说"我可以提交",要么"我必须回滚".这个过程有些曲折; 例如,事务方法可以调用另一个事务方法并共享同一个事务.
虽然事务管理与互动的DataSource
,它不拥有的DataSource
.您不能要求事务管理器为您提供连接.相反,您必须注入一个将返回连接的特定于帧的对象(例如Hibernate SessionFactory
).或者,您可以使用静态事务感知实用程序类,但这些类又与特定框架相关联.
您可以尝试DataSourceUtils.getConnection(dataSource)
,根据API,它应该返回数据源的当前连接.
更新:
根据您的评论和源代码org.springframework.transaction.support.TransactionSynchronizationManager
:
就像我说的,获取连接的关键是数据源名称,如果无法获得,通过查看源代码的一种方法是尝试这样做:
TransactionSynchronizationManager.getResourceMap()
将返回当前线程中的数据源映射到ConnectionHolder,假设您只有1个资源涉及事务,您可以执行a map.values().get(0)
获取第一个ConnectionHolder,您可以通过调用获取连接.getConnection()
所以基本上要求以下内容:
TransactionSynchronizationManager.getResourceMap().values().get(0).getConnection()
可能必须有更好的方式:-)
我假设您使用的是普通 Jdbc,您需要做的是:
BaseDao {
@Autowired
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Connection getConnection() {
// ....use dataSource to create connection
return DataSourceUtils.getConnection(dataSource);
}
}
FooDao extends BaseDao {
// your foo() method
void foo() {
Connection conn = getConnection();
//....
}
}
Run Code Online (Sandbox Code Playgroud)
所有这一切有点令人恼火的是,Spring 文档主要是用营销语言编写的,隐藏了幕后的丑陋。
明确地说:
您的数据源存储在线程本地上下文中,这是基于(大多数有效)假设请求始终由唯一线程处理。
因此,Spring 以一种非常复杂的方式所做的就是将您的内容本地存储到您当前的执行线程中,这是一件微不足道的事情,但在整个 Spring 文档中重复得不够清楚。Spring 基本上把你的东西放到一个“全局上下文”中,以避免将它拉到你所有的接口和方法定义中。乍一看有点神奇,但实际上只是化妆。
因此,您最终会调用静态 DataSourceUtils 方法来检索您的内容。