Java 如何获取Spring事务内部的连接?
想象一下这个代码:Java 如何获取Spring事务内部的连接?,java,spring,jdbc,connection,spring-transactions,Java,Spring,Jdbc,Connection,Spring Transactions,想象一下这个代码: foo() { Connection conn = ...; } foo()已从具有注释@Transactional的方法调用。如何获取当前的JDBC连接?请注意,foo()在bean中(因此它可以有@Autowired字段),但是foo()不能有参数(因此我不能从某个地方传递连接) [EDIT]我正在使用jOOQ,它需要数据源或连接。我的问题:我不知道配置了哪个事务管理器。它可以是任何东西;JavaEE,基于数据源,通过JNDI获取数据源。我的代码不是一个应用程
foo() {
Connection conn = ...;
}
foo()
已从具有注释@Transactional
的方法调用。如何获取当前的JDBC连接?请注意,foo()
在bean中(因此它可以有@Autowired
字段),但是foo()
不能有参数(因此我不能从某个地方传递连接)
[EDIT]我正在使用jOOQ,它需要数据源或连接。我的问题:我不知道配置了哪个事务管理器。它可以是任何东西;JavaEE,基于数据源,通过JNDI获取数据源。我的代码不是一个应用程序,而是一个库。我需要吞下别人放在我盘子里的东西。同样,我不能请求Hibernate会话工厂,因为使用我的应用程序可能不使用Hibernate
但是我知道其他代码,比如Spring Hibernate集成,可以通过某种方式从事务管理器获取当前连接。我的意思是,Hibernate不支持Spring的事务管理器,因此粘合代码必须使SpringAPI适应Hibernate的期望。我需要做同样的事情,但我不知道它是如何工作的
[EDIT2]我知道有一个活动事务(即Spring在某处有一个连接实例,或者至少有一个可以创建一个的事务管理器),但我的方法不是@Transactional。我需要调用以
java.sql.Connection
为参数的构造函数。我应该怎么做?如果您在JDBC中使用Spring事务,请配置JdbcTemplate
,并使用JdbcTemplate.execute(ConnectionCallback)
访问当前事务。这是访问Spring配置的连接的标准方法。我假设您使用的是普通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();
//....
}
}
您可能可以尝试使用
DataSourceUtils.getConnection(dataSource)
,它应该返回数据源的当前连接
更新:
根据您的评论和org.springframework.transaction.support.TransactionSynchronizationManager的源代码:
正如我所说,获取连接的关键是数据源名称,如果无法获取,查看源代码的一种方法是尝试以下方法:
TransactionSynchronizationManager.getResourceMap()
将返回数据源到当前线程中ConnectionHolder的映射,假设事务中只涉及1个资源,您可能可以执行map.values().get(0)
以获取第一个ConnectionHolder,通过调用.getConnection()
因此,本质上称之为:
TransactionSynchronizationManager.getResourceMap().values().get(0.getConnection()
不过,可能必须有更好的方法:-)(完全根据评论线程重写;不确定我最初的答案为什么集中在Hibernate上,而不是我现在正在使用的)
事务管理器与数据源完全正交。有些事务管理器直接与数据源交互,有些通过中间层(例如Hibernate)交互,有些通过容器提供的服务(例如JTA)交互
当您将一个方法标记为@Transactional
时,这意味着Spring将在加载您的bean时生成一个代理,该代理将被交给希望使用您的bean的任何其他类。当调用代理的方法时,它(代理)要求事务管理器为其提供一个未完成的事务或创建一个新的事务。然后它调用实际的bean方法。当bean方法返回时,代理再次与事务管理器交互,要么说“我可以提交”,要么说“我必须回滚”。这个过程有曲折;例如,一个事务性方法可以调用另一个事务性方法并共享同一个事务
当事务管理器与
数据源
交互时,它并不拥有数据源
。您不能要求事务管理器为您提供连接。相反,必须插入一个特定于帧的对象,该对象将返回连接(例如HibernateSessionFactory
)。或者,您可以使用静态事务感知实用程序类,但这些类又与特定的框架相关联。所有这些都有点令人恼火的是,Spring文档主要是用营销语言编写的,隐藏了幕后的丑陋
简而言之:
您的数据源存储在线程本地上下文中,这是基于请求总是由唯一线程处理的假设(基本上是有效的)
因此,Spring以一种非常复杂的方式将您的内容本地存储到当前的执行线程中,这是一件微不足道的事情,但在Spring文档中没有足够清晰地重复。Spring基本上将您的东西放在“全局上下文”中,以避免通过所有接口和方法定义来实现它。一开始看起来有点神奇,但实际上只是化妆而已
因此,您最终将使用静态DataSourceUtils方法调用来检索您的资料。3其他方法:
@组件
公共类MyServicentransactional{
@自动连线
私有事务模板TransactionTemplate;
@自动连线
私有数据源;
公共空间{
transactionTemplate.executeWithoutResult(状态->{
Connection Connection=DataSourceUtils.getConnection(dataSource);
//我们走吧。。。
});
}
}
@服务
公共类MyServiceTransaction{
@自动连线
私有数据源;
@交易的
公共空间{
Connection Connection=DataSourceUtils.getConnection(dataSource);