交易支持
习惯于使用关系数据库进入 LDAP 世界的程序员经常对没有事务概念这一事实表示惊讶。它没有在协议中指定,也没有 LDAP 服务器支持它。认识到这可能是一个主要问题,Spring LDAP 为客户端提供对 LDAP 资源的补偿事务的支持。
LDAP 事务支持由ContextSourceTransactionManager
一个PlatformTransactionManager
管理 Spring 事务对 LDAP作的支持的实现。它与其合作者一起跟踪事务中执行的 LDAP作,记录每个作之前的状态,并在需要回滚事务时采取措施恢复初始状态。
除了实际的事务管理外,Spring LDAP 事务支持还确保了DirContext
实例在同一事务中使用。也就是说,DirContext
在事务完成之前实际上不会关闭,从而可以更有效地利用资源。
虽然 Spring LDAP 用于提供事务支持的方法在许多情况下已经足够了,但它绝不是传统意义上的“真实”事务。服务器完全不知道事务,因此(例如),如果连接中断,则无法回滚事务。虽然应该仔细考虑这一点,但也应该注意,另一种选择是在没有任何事务支持的情况下运行。Spring LDAP 的事务支持几乎是最好的。 |
除了原始作所需的工作之外,客户端事务支持还增加了一些开销。虽然在大多数情况下不应担心此开销,如果您的应用程序不在同一事务中执行多个 LDAP作(例如,modifyAttributes 其次rebind ), 或者,如果不需要与 JDBC 数据源进行事务同步(参见 JDBC 事务集成),那么使用 LDAP 事务支持几乎没有什么好处。 |
配置
如果您习惯于配置 Spring 事务,那么配置 Spring LDAP 事务应该看起来非常熟悉。您可以使用@Transactional
,创建一个TransactionManager
实例,并包含一个<tx:annotation-driven>
元素。以下示例显示了如何执行此作:
<ldap:context-source
url="ldap://localhost:389"
base="dc=example,dc=com"
username="cn=Manager"
password="secret" />
<ldap:ldap-template id="ldapTemplate" />
<ldap:transaction-manager>
<!--
Note this default configuration will not work for more complex scenarios;
see below for more information on RenamingStrategies.
-->
<ldap:default-renaming-strategy />
</ldap:transaction-manager>
<!--
The MyDataAccessObject class is annotated with @Transactional.
-->
<bean id="myDataAccessObject" class="com.example.MyRepository">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<tx:annotation-driven />
...
虽然此设置适用于大多数简单的用例,但一些更复杂的场景需要额外的配置。具体来说,如果您需要在事务中创建或删除子树,则需要使用替代方法TempEntryRenamingStrategy ,如重命名策略中所述。 |
在实际情况下,您可能会在服务对象级别而不是存储库级别应用事务。前面的示例演示了一般思想。
JDBC 事务集成
使用 LDAP 时的一个常见用例是,某些数据存储在 LDAP 树中,但其他数据存储在关系数据库中。在这种情况下,事务支持变得更加重要,因为不同资源的更新应该同步。
虽然不支持实际的 XA 事务,但通过提供data-source-ref
属性添加到<ldap:transaction-manager>
元素。 这会创建一个ContextSourceAndDataSourceTransactionManager
,然后它实际上管理两个事务,就好像它们是一个事务一样。执行提交时,始终首先执行作的 LDAP 部分,以便在 LDAP 提交失败时回滚这两个事务。事务的 JDBC 部分的管理方式与DataSourceTransactionManager
,但不支持嵌套事务。以下示例显示了ldap:transaction-manager
元素与data-source-ref
属性:
<ldap:transaction-manager data-source-ref="dataSource" >
<ldap:default-renaming-strategy />
<ldap:transaction-manager />
提供的支持都是客户端的。 包装的事务不是 XA 事务。不执行两阶段提交,因为 LDAP 服务器无法对其结果进行投票。 |
您可以通过提供session-factory-ref
属性添加到<ldap:transaction-manager>
元素,如下所示:
<ldap:transaction-manager session-factory-ref="dataSource" >
<ldap:default-renaming-strategy />
<ldap:transaction-manager />
LDAP 补偿事务说明
Spring LDAP 通过在每次修改作(bind
,unbind
,rebind
,modifyAttributes
和rename
).
这允许系统在需要回滚事务时执行补偿作。
在许多情况下,补偿作非常简单。例如,对bind
作是解绑条目。
但是,由于 LDAP 数据库的一些特殊特征,其他作需要不同的、更复杂的方法。
具体来说,并不总是能够获得所有Attributes
,使得上述策略不足以(例如)一个unbind
操作。
这就是为什么在 Spring LDAP 托管事务中执行的每个修改作在内部都分为四个不同的作:记录作、 准备作、提交作和回滚作。下表描述了每个 LDAP作:
LDAP作 | 录音 | 制备 | 犯 | 反转 |
---|---|---|---|---|
|
记录要绑定的条目的DN。 |
绑定条目。 |
没有作。 |
使用记录的 DN 取消绑定条目。 |
|
记录原始 DN 和目标 DN。 |
重命名条目。 |
没有作。 |
将条目重命名回其原始 DN。 |
|
记录原始DN并计算临时DN。 |
将条目重命名为临时位置。 |
解绑临时条目。 |
将条目从临时位置重命名回其原始 DN。 |
|
记录原始 DN 和新 |
将条目重命名为临时位置。 |
绑定新的 |
将条目从临时位置重命名回其原始 DN。 |
|
记录条目的DN以修改和计算补偿 |
执行 |
没有作。 |
执行 |
Javadoc 中提供了 Spring LDAP 事务支持的内部工作原理的更详细描述。
重命名策略
如上一节的表所述,某些作的事务管理需要暂时重命名受作影响的原始条目,然后才能在提交中进行实际修改。计算条目的临时 DN 的方式由TempEntryRenamingStrategy
在<ldap:transaction-manager >
声明。Spring LDAP 包括两个实现:
-
DefaultTempEntryRenamingStrategy
(默认值):通过使用<ldap:default-renaming-strategy />
元素。向条目 DN 的最低有效部分添加后缀。例如,对于 DN 为cn=john doe, ou=users
,则此策略返回临时 DNcn=john doe_temp, ou=users
.您可以通过设置temp-suffix
属性。 -
DifferentSubtreeTempEntryRenamingStrategy
:使用<ldap:different-subtree-renaming-strategy />
元素。它将子树 DN 附加到 DN 的最低有效部分。这样做会使所有临时条目都放置在 LDAP 树中的特定位置。临时子树 DN 是通过设置subtree-node
属性。例如,如果subtree-node
是ou=tempEntries
条目的原始 DN 为cn=john doe, ou=users
,则临时 DN 为cn=john doe, ou=tempEntries
.请注意,配置的子树节点需要存在于 LDAP 树中。
这DefaultTempEntryRenamingStrategy 在某些情况下不起作用。例如,如果您计划进行递归删除,则需要使用DifferentSubtreeTempEntryRenamingStrategy .这是因为递归删除作实际上包括对子树中每个节点的深度优先删除。由于您无法重命名具有任何子项和DefaultTempEntryRenamingStrategy 将每个节点保留在同一个子树中(具有不同的名称)而不是实际删除它,则此作将失败。如有疑问,请使用DifferentSubtreeTempEntryRenamingStrategy . |