shareingjdbc 读写分离 druid 不能批量更新
时间: 2023-09-06 18:02:40 浏览: 45
SharingJDBC 是一个用于读写分离的 Java 数据库中间件,可以通过将读操作和写操作分别路由到不同的数据库节点,以提高数据库读写能力和性能。
Druid 是一个开源的数据库连接池组件,它提供了连接池管理、SQL 解析、SQL 优化、SQL 状态监控和统计以及批量处理等功能。然而,Druid 在进行批量更新操作时存在一定的限制。
具体而言,Druid 的批量更新操作是通过 JDBC 的批处理机制来实现的,即将一批更新操作打包成一个批次进行执行。但是,由于数据库的不同实现,对批量更新的支持程度各不相同。有些数据库如 MySQL 对批量更新的支持非常好,而有些数据库如 Oracle 的支持则相对较弱。
因此,由于数据库的差异性,Druid 在进行批量更新操作时可能会遇到一些限制,特别是在某些数据库环境下。在这种情况下,即使使用了 SharingJDBC 进行读写分离,也不能解决 Druid 本身的批量更新限制。
为解决这个问题,我们可以考虑以下几种方案:
1. 如果数据库支持批量更新操作,可以尝试使用数据库的原生批量更新功能,而不是依赖于 Druid 的批量处理机制。
2. 对于不支持或支持较弱的数据库,可以通过自行编写代码,将多次更新操作组织在同一个事务中,以减少数据库的交互次数,并提高性能。
3. 如果对批量更新操作的性能要求不高,也可以将更新操作拆分成多个单个更新操作,逐一执行。
总之,虽然 Druid 在某些数据库环境下可能不能进行高效的批量更新操作,但我们可以通过其他手段来解决这个问题,以提高系统的性能和可靠性。
相关问题
springboot+mybatisplus+druid实现读写分离
实现读写分离可以利用 SpringBoot、MybatisPlus 和 Druid 进行配置。下面是一个简单的实现过程:
1. 添加 MybatisPlus 和 Druid 的 Maven 依赖。
```xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
```
2. 在配置文件中添加 Druid 数据源相关配置。
```yaml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/db_name?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
initialSize: 5
maxActive: 10
minIdle: 5
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
```
3. 配置 MybatisPlus 的多数据源功能。
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.getType(), masterDataSource);
targetDataSources.put(DataSourceType.SLAVE.getType(), slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
}
```
4. 创建一个 DataSourceHolder 类,用于保存当前线程的数据源类型。
```java
public class DataSourceHolder {
private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();
public static String getDataSource() {
return HOLDER.get();
}
public static void setDataSource(String dataSource) {
HOLDER.set(dataSource);
}
public static void clearDataSource() {
HOLDER.remove();
}
}
```
5. 创建一个枚举类型 DataSourceType,用于表示数据源类型。
```java
public enum DataSourceType {
MASTER("master"),
SLAVE("slave");
private final String type;
DataSourceType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
```
6. 创建一个 DynamicDataSource 类,继承 AbstractRoutingDataSource,用于动态切换数据源。
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
private final Map<Object, Object> targetDataSources;
public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultDataSource);
this.targetDataSources = targetDataSources;
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
this.targetDataSources.putAll(targetDataSources);
super.setTargetDataSources(this.targetDataSources);
super.afterPropertiesSet();
}
@Override
public void addTargetDataSource(Object key, Object dataSource) {
this.targetDataSources.put(key, dataSource);
super.setTargetDataSources(this.targetDataSources);
super.afterPropertiesSet();
}
}
```
7. 创建一个 AopDataSourceConfig 类,用于配置切面,实现动态切换数据源。
```java
@Configuration
public class AopDataSourceConfig {
@Bean
public DataSourceAspect dataSourceAspect() {
return new DataSourceAspect();
}
}
```
```java
@Aspect
public class DataSourceAspect {
@Pointcut("@annotation(com.example.demo.annotation.Master) " +
"|| execution(* com.example.demo.service..*.select*(..)) " +
"|| execution(* com.example.demo.service..*.get*(..)) " +
"|| execution(* com.example.demo.service..*.query*(..)) " +
"|| execution(* com.example.demo.service..*.find*(..)) " +
"|| execution(* com.example.demo.service..*.count*(..))")
public void read() {
}
@Pointcut("execution(* com.example.demo.service..*.insert*(..)) " +
"|| execution(* com.example.demo.service..*.update*(..)) " +
"|| execution(* com.example.demo.service..*.delete*(..))")
public void write() {
}
@Around("read()")
public Object read(ProceedingJoinPoint joinPoint) throws Throwable {
try {
DataSourceHolder.setDataSource(DataSourceType.SLAVE.getType());
return joinPoint.proceed();
} finally {
DataSourceHolder.clearDataSource();
}
}
@Around("write()")
public Object write(ProceedingJoinPoint joinPoint) throws Throwable {
try {
DataSourceHolder.setDataSource(DataSourceType.MASTER.getType());
return joinPoint.proceed();
} finally {
DataSourceHolder.clearDataSource();
}
}
}
```
8. 在 Service 层的方法上使用 @Master 注解,表示强制使用主库。
```java
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
@Master
public boolean save(User user) {
return super.save(user);
}
}
```
这样就实现了读写分离功能。需要注意的是,在使用 MybatisPlus 进行 CRUD 操作时,需要使用对应的 Service 方法,例如 selectList、selectPage、insert、updateById、deleteById,而不是直接调用 Mapper 方法。否则,数据源切换将不会生效。
springboot通过Druid实现redis+mysql的读写分离示例
Springboot可以通过Druid实现redis和mysql的读写分离,下面是一个示例:
1. 在pom.xml中添加依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
2. 在application.yml中配置redis和mysql的读写分离:
spring:
datasource:
druid:
# Redis数据源
redis:
url: jdbc:redis://127.0.0.1:6379/0
driver-class-name: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
# MySQL数据源
mysql:
url: jdbc:mysql://127.0.0.1:3306/test
driver-class-name: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
3. 在Springboot启动类中添加@EnableDruid注解:
@SpringBootApplication
@EnableDruid
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. 配置Druid数据源:
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.redis")
public DataSource redisDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.mysql")
public DataSource mysqlDataSource() {
return DruidDataSourceBuilder.create().build();
}
}
5. 在Service层中实现读写分离:
@Service
public class UserService {
@Autowired
private DataSource redisDataSource;
@Autowired
private DataSource mysqlDataSource;
public void saveUser() {
// 使用MySQL数据源写入数据
DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MYSQL);
// ...
// 使用Redis数据源读取数据
DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.REDIS);
// ...
}
}