天天看点

SpringBoot中数据源读写分离配置

       开发中常用到主从数据库来提高系统的性能。怎么样才能方便的实现主从读写分离呢? 通过事务注解里面的可读属性readOnly的取值来自动切换数据源, 从而实现数据库读写分离。

1.主备数据源配置

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

@Configuration

@PropertySources

({

@PropertySource

(

"classpath:travel.properties"

)})

@EnableTransactionManagement

@MapperScan

(basePackages = 

"com.ethen.travel"

, annotationClass = Mapper.

class

, sqlSessionFactoryRef = 

"sqlSessionFactory"

)

public

class

DataSourceConfig {

@Autowired

private

Environment props;

private

BasicDataSource abstractDataSource() {

BasicDataSource abstractDataSource = 

new

BasicDataSource();

abstractDataSource.setDriverClassName(props.getProperty(

"db.driverClassName"

));

abstractDataSource.setUsername(props.getProperty(

"db.username"

));

abstractDataSource.setPassword(props.getProperty(

"db.password"

));

abstractDataSource.setTestOnBorrow(

true

);

abstractDataSource.setTestWhileIdle(

true

);

abstractDataSource.setValidationQuery(

"SELECT 1"

);

abstractDataSource.setTimeBetweenEvictionRunsMillis(

300000

);

abstractDataSource.setNumTestsPerEvictionRun(

10

);

abstractDataSource.setMinEvictableIdleTimeMillis(-

1

);

abstractDataSource.setPoolPreparedStatements(

true

);

abstractDataSource.setMaxOpenPreparedStatements(

100

);

return

abstractDataSource;

}

@Bean

(destroyMethod = 

"close"

, name=

"master"

)

@Primary

public

BasicDataSource masterDataSource() {

BasicDataSource masterDataSource = abstractDataSource();

masterDataSource.setUrl(props.getProperty(

"db.master.url"

));

masterDataSource.setMaxTotal(Integer.parseInt(props.getProperty(

"db.master.maxActive"

)));

masterDataSource.setMaxIdle(Integer.parseInt(props.getProperty(

"db.master.maxIdle"

)));

masterDataSource.setMinIdle(Integer.parseInt(props.getProperty(

"db.master.maxIdle"

)));

return

masterDataSource;

}

@Bean

(destroyMethod = 

"close"

, name=

"slave"

)

public

BasicDataSource slaveDataSource() {

BasicDataSource masterDataSource = abstractDataSource();

masterDataSource.setUrl(props.getProperty(

"db.slave.url"

));

masterDataSource.setMaxTotal(Integer.parseInt(props.getProperty(

"db.slave.maxActive"

)));

masterDataSource.setMaxIdle(Integer.parseInt(props.getProperty(

"db.slave.maxIdle"

)));

masterDataSource.setMinIdle(Integer.parseInt(props.getProperty(

"db.slave.maxIdle"

)));

return

masterDataSource;

}

@Bean

(name=

"dynamicDataSource"

)

public

ReplicationRoutingDataSource dynamicDataSource() 

throws

IOException {

Map<Object, Object> targetDataSources = 

new

HashMap<>();

targetDataSources.put(

"master"

, masterDataSource());

targetDataSources.put(

"slave"

, slaveDataSource());

ReplicationRoutingDataSource dynamicDataSource = 

new

ReplicationRoutingDataSource();

dynamicDataSource.setDefaultTargetDataSource(targetDataSources.get(

"master"

));

dynamicDataSource.setTargetDataSources(targetDataSources);

return

dynamicDataSource;

}

public

DataSource dataSource() 

throws

IOException {

return

new

LazyConnectionDataSourceProxy(dynamicDataSource());

}

@Bean

public

SqlSessionFactory sqlSessionFactory() 

throws

Exception {

SqlSessionFactoryBean sqlFactory = 

new

SqlSessionFactoryBean();

sqlFactory.setDataSource(dataSource());

sqlFactory.setConfigLocation(

new

ClassPathResource(

"mybatis-config.xml"

));

sqlFactory.setTypeAliasesPackage(

"com.ethen.travel"

);

return

sqlFactory.getObject();

}

@Bean

public

DataSourceTransactionManager txManager() 

throws

IOException {

DataSourceTransactionManager dataSourceTXManager = 

new

DataSourceTransactionManager();

dataSourceTXManager.setDataSource(dataSource());

AnnotationTransactionAspect.aspectOf().setTransactionManager(dataSourceTXManager);

return

dataSourceTXManager;

}

}

2.数据源动态切换

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

@Slf4j

public

class

ReplicationRoutingDataSource 

extends

AbstractRoutingDataSource {

private

static

final

String SLAVE_LOOKUP_KEY = 

"slave"

;

private

static

final

String MASTER_LOOKUP_KEY = 

"master"

;

@Override

protected

Object determineCurrentLookupKey() {

String lookupKey = TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? SLAVE_LOOKUP_KEY : MASTER_LOOKUP_KEY;

log.debug(

"connected DataSource :{}"

, lookupKey);

return

lookupKey;

}

}

    上面只贴出了关键代码,数据库的配置文件就没有贴出来了。这样就可以很方便的实现的主从数据源动态切换,实现读写分离。

继续阅读