有这样一个需求,某分库分表中间件做了读写分离的路由,依据的是事务的readOnly属性。但是读写分离会有一定的延迟,因此不适合将全部读操作都放在从库,而是应该将部分实时性依赖低的查询操作放在从库,但是接口都是统一提供的,想根据接口入参实时调整事务的readOnly属性的想法就出现了。
通过继承修改 DataSourceTransactionManager,将TransactionDefinition 包装为我们自己的DynamicTransactionDefinition
package xxxxxxx.dao.common;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
/**
* Created by lxn on 2019/5/16.
*/
public class DynamicReadOnlyTrancationManager extends DataSourceTransactionManager {
@Value("${read_only_enable}")
private Boolean readOnlyEnable;
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
if (readOnlyEnable){
super.doBegin(transaction, new DynamicTransactionDefinition(definition));
}else {
super.doBegin(transaction, definition);
}
}
}
动态Definition包装类
package xxxxxxx.dao.common;
import org.springframework.transaction.TransactionDefinition;
/**
* Created by lxn on 2019/5/16.
*/
public class DynamicTransactionDefinition implements TransactionDefinition {
private TransactionDefinition org;
public DynamicTransactionDefinition(TransactionDefinition org) {
this.org = org;
}
@Override
public int getPropagationBehavior() {
return org.getPropagationBehavior();
}
@Override
public int getIsolationLevel() {
return org.getIsolationLevel();
}
@Override
public int getTimeout() {
return org.getTimeout();
}
@Override
public boolean isReadOnly() {
//某线程变量中获取
return OperatorUtil.getOperator().isReadOnly();
}
@Override
public String getName() {
return org.getName();
}
}
这样我们就通过装饰的设计模式,修改了Definition 的行为,欺骗了spring 的 TransactionManager
最后别忘了配置我们自己的TransactionManager
<bean id="cdsTransactionManager" class="xxxxxxxx.dao.common.DynamicReadOnlyTrancationManager">
<property name="dataSource" ref="cdsDataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="cdsTransactionManager" />