AbstractRoutingDataSource继承自 Spring 的
AbstractDataSource 类,并实现了 DataSource接口。它内部维护了一个映射(Map), 用于存储数据源标识和对应的数据源实例。当需要获取连接时, AbstractRoutingDataSource会调用一个抽象方法 determineCurrentLookupKey()来确定当前的数据源标识, 然后根据这个标识从映射中获取对应的数据源,并从该数据源中获取连接。
public class DynamicDataSource extends AbstractRoutingDataSource {
// 取得当前使用哪个数据源
@Override
protected Object determineCurrentLookupKey() {
return "当前数据源";
}
}
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
private Map<Object, Object> targetDataSources;//所有数据源(需要指定)
private Object defaultTargetDataSource;//默认数据源(需要指定)
private boolean lenientFallback = true;
private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();//数据源查找
private Map<Object, DataSource> resolvedDataSources;//已解析的数据源
private DataSource resolvedDefaultDataSource;//已解析默认数据源
}
`AbstractRoutingDataSource` 是 Spring 提供的一个抽象类,用于实现动态数据源路由。它的核心在于 `determineCurrentLookupKey` 方法,该方法用于确定当前线程应该使用哪个数据源。
在 `AbstractRoutingDataSource` 中,`determineCurrentLookupKey` 方法是一个抽象方法,需要由子类实现。Spring 在执行数据库操作时会调用这个方法,根据返回的键值(lookup key)来决定使用哪个数据源。这个方法通常结合 `ThreadLocal` 来实现,以便在一次数据库操作中保持数据源的一致性。
`AbstractRoutingDataSource` 的工作原理如下:
1. 它维护了一个数据源映射(`Map<Object, Object> targetDataSources`),其中的键是数据源的键,值是数据源对象。
2. `afterPropertiesSet` 方法在初始化时会被调用,它会将 `targetDataSources` 映射解析为 `resolvedDataSources`,以便快速查找。
3. `determineTargetDataSource` 方法在获取连接时被调用,它使用 `determineCurrentLookupKey` 方法来获取当前线程应该使用的数据源键,然后从 `resolvedDataSources` 中获取对应的数据源对象。
当实现 `determineCurrentLookupKey` 方法时,通常会使用 `ThreadLocal` 来存储当前线程的数据源键。这样,就可以在运行时动态地切换数据源,而不需要重启应用程序。
在实际应用中,可以通过在方法执行前后切换 `ThreadLocal` 中的数据源键来实现数据源的动态切换。例如,可以在一个事务的开始时设置一个特定的数据源键,然后在事务结束时清除该键,以恢复到默认数据源。
总结来说,`determineCurrentLookupKey` 方法的作用是确定当前线程应该使用哪个数据源,这是实现动态数据源切换的关键。通过继承 `AbstractRoutingDataSource` 并实现这个方法,可以在不同的数据源之间进行灵活切换,以满足多数据源配置、读写分离、分库分表等场景的需求。
@EnableTransactionManagement和 @Transactional 的区别
`@EnableTransactionManagement` 和 `@Transactional` 是 Spring 框架中用于事务管理的两个不同的注解,它们的作用和用途有所区别:
1. **@EnableTransactionManagement**:
- 这是一个类级别的注解,用于开启基于注解的事务管理。
- 当你在一个配置类上使用 `@EnableTransactionManagement` 时,它告诉 Spring 框架要激活事务管理的支持,并且扫描使用了 `@Transactional` 注解的方法或类。
- 这个注解通常只在一个配置类中使用一次,因为它会激活整个应用程序上下文中的事务管理支持。
- `@EnableTransactionManagement` 是一个复合注解,它包含了 `@EnableAspectJAutoProxy`,这意味着它也会启用 Spring 的 AspectJ 自动代理支持。
2. **@Transactional**:
- 这是一个方法或类级别的注解,用于声明事务的边界和属性。
- 当你在一个方法或类上使用 `@Transactional` 时,你告诉 Spring 框架这个方法或类中的所有方法应该在事务的上下文中执行。
- `@Transactional` 注解可以指定多个事务属性,如传播行为(propagation)、隔离级别(isolation)、超时时间(timeout)、只读标志(readOnly)等。
- 这个注解可以被多次使用,每次使用都可以定义不同的事务属性。
### 示例:
```java
@Configuration
@EnableTransactionManagement // 开启基于注解的事务管理
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
@Service
public class MyService {
@Transactional // 声明这个方法在事务的上下文中执行
public void myTransactionalMethod() {
// 方法内的业务逻辑将被事务管理
}
}
```
在这个例子中,`@EnableTransactionManagement` 用于配置类 `TransactionConfig` 中,它启用了事务管理。而 `@Transactional` 用于 `MyService` 类的 `myTransactionalMethod` 方法上,它确保这个方法在事务的上下文中执行。
总结来说,`@EnableTransactionManagement` 是一个开启事务管理功能的开关,而 `@Transactional` 是一个用于具体方法或类上,定义事务属性的注解。两者结合使用,为 Spring 应用程序提供了声明式的事务管理能力。