Skip to content

Commit ca0240d

Browse files
author
nononi
committed
基于AbstractRoutingDataSource自动切换数据源
1 parent 3d328f2 commit ca0240d

File tree

7 files changed

+225
-0
lines changed

7 files changed

+225
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.nononi.dynamicdb.annotation;
2+
3+
import org.springframework.stereotype.Component;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Target(ElementType.METHOD)
11+
@Retention(RetentionPolicy.RUNTIME)
12+
@Component
13+
public @interface ReadOnly {
14+
15+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.nononi.dynamicdb.aspect;
2+
3+
import io.nononi.dynamicdb.annotation.ReadOnly;
4+
import io.nononi.dynamicdb.datasource.DynamicDataSource;
5+
import org.aspectj.lang.ProceedingJoinPoint;
6+
import org.aspectj.lang.annotation.Around;
7+
import org.aspectj.lang.annotation.Aspect;
8+
import org.aspectj.lang.annotation.Pointcut;
9+
import org.aspectj.lang.reflect.MethodSignature;
10+
import org.springframework.stereotype.Component;
11+
12+
import java.lang.reflect.Method;
13+
14+
@Aspect
15+
@Component
16+
public class ReadOnlyAspect {
17+
18+
@Pointcut("@annotation(io.nononi.dynamicdb.annotation.ReadOnly)")
19+
public void readOnly(){};
20+
21+
22+
@Around("readOnly()")
23+
public Object around(ProceedingJoinPoint point) throws Throwable{
24+
MethodSignature signature = (MethodSignature) point.getSignature();
25+
Method method = signature.getMethod();
26+
27+
ReadOnly readOnly = method.getAnnotation(ReadOnly.class);
28+
if(readOnly == null){
29+
DynamicDataSource.setDataSource("master");
30+
System.out.println("datasource is :" + "master");
31+
} else {
32+
DynamicDataSource.setDataSource("slave");
33+
System.out.println("datasource is :" + "slave");
34+
}
35+
36+
try {
37+
return point.proceed();
38+
}finally {
39+
DynamicDataSource.clearDataSource();
40+
System.out.println("clean datasource");
41+
}
42+
}
43+
44+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.nononi.dynamicdb.datasource;
2+
3+
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
4+
5+
import javax.sql.DataSource;
6+
import java.util.Map;
7+
8+
public class DynamicDataSource extends AbstractRoutingDataSource {
9+
10+
11+
/**
12+
* threadLocal 设置数据源
13+
*/
14+
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
15+
16+
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources){
17+
super.setDefaultTargetDataSource(defaultTargetDataSource);
18+
super.setTargetDataSources(targetDataSources);
19+
super.afterPropertiesSet();
20+
}
21+
22+
@Override
23+
protected Object determineCurrentLookupKey() {
24+
return getDataSource();
25+
}
26+
27+
public static void setDataSource(String dataSource) {
28+
CONTEXT_HOLDER.set(dataSource);
29+
}
30+
31+
public static String getDataSource() {
32+
return CONTEXT_HOLDER.get();
33+
}
34+
35+
public static void clearDataSource() {
36+
CONTEXT_HOLDER.remove();
37+
}
38+
39+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.nononi.dynamicdb.datasource;
2+
3+
import org.springframework.beans.factory.annotation.Qualifier;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.context.annotation.Primary;
7+
import org.springframework.jdbc.datasource.DriverManagerDataSource;
8+
9+
import javax.sql.DataSource;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
@Configuration
14+
public class DynamicDataSourceConfig {
15+
16+
@Bean(name = "master")
17+
public DataSource masterDatasource(){
18+
DriverManagerDataSource dataSource = new DriverManagerDataSource();
19+
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
20+
dataSource.setUrl("jdbc:mysql://localhost:3316/db");
21+
dataSource.setUsername("root");
22+
dataSource.setPassword("");
23+
return dataSource;
24+
}
25+
26+
@Bean(name = "slave")
27+
public DataSource slaveDatasource(){
28+
DriverManagerDataSource dataSource = new DriverManagerDataSource();
29+
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
30+
dataSource.setUrl("jdbc:mysql://localhost:3326/db");
31+
dataSource.setUsername("root");
32+
dataSource.setPassword("");
33+
return dataSource;
34+
}
35+
36+
@Bean
37+
@Primary
38+
public DynamicDataSource dataSource(@Qualifier("master") DataSource masterDatasource, @Qualifier("slave") DataSource slaveDatasource){
39+
Map<Object, Object> targetDataSources = new HashMap<>();
40+
targetDataSources.put("master", masterDatasource);
41+
targetDataSources.put("slave",slaveDatasource);
42+
return new DynamicDataSource(masterDatasource,targetDataSources);
43+
}
44+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.nononi.dynamicdb.service;
2+
3+
public interface OrderService {
4+
void insert(int id ,String name);
5+
void query();
6+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package io.nononi.dynamicdb.service.impl;
2+
3+
import io.nononi.dynamicdb.annotation.ReadOnly;
4+
import io.nononi.dynamicdb.datasource.DynamicDataSource;
5+
import io.nononi.dynamicdb.service.OrderService;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.stereotype.Component;
8+
9+
import java.sql.Connection;
10+
import java.sql.PreparedStatement;
11+
import java.sql.ResultSet;
12+
import java.sql.SQLException;
13+
14+
@Component
15+
public class OrderServiceImpl implements OrderService {
16+
17+
@Autowired
18+
private DynamicDataSource dataSource;
19+
20+
@Override
21+
public void insert(int id, String name) {
22+
try {
23+
Connection conn = dataSource.getConnection();
24+
System.out.println(conn.getMetaData().getURL());
25+
String sql = "INSERT INTO `order` (id,name) VALUES (?,?);";
26+
PreparedStatement stmt = conn.prepareStatement(sql);
27+
stmt.setInt(1,id);
28+
stmt.setString(2,name);
29+
stmt.executeUpdate();
30+
31+
} catch (SQLException e) {
32+
e.printStackTrace();
33+
}
34+
35+
}
36+
37+
@Override
38+
@ReadOnly
39+
public void query() {
40+
String sql = "SELECT * FROM `order`;";
41+
try {
42+
Connection conn = dataSource.getConnection();
43+
System.out.println(conn.getMetaData().getURL());
44+
PreparedStatement stmt = conn.prepareStatement(sql);
45+
ResultSet resultSet = stmt.executeQuery();
46+
while (resultSet.next()) {
47+
System.out.print(resultSet.getInt("id") + " ");
48+
System.out.println(resultSet.getString("name") + " ");
49+
}
50+
} catch (SQLException e) {
51+
e.printStackTrace();
52+
}
53+
54+
}
55+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.nononi.dynamicdb;
2+
3+
import io.nononi.dynamicdb.service.impl.OrderServiceImpl;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.api.extension.ExtendWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.test.context.junit.jupiter.SpringExtension;
9+
10+
@SpringBootTest
11+
@ExtendWith(SpringExtension.class)
12+
class DynamicdbApplicationTests {
13+
@Autowired
14+
private OrderServiceImpl orderService;
15+
16+
@Test
17+
public void testDynamicDb(){
18+
orderService.insert(4,"ohhhhhh");
19+
orderService.query();
20+
}
21+
22+
}

0 commit comments

Comments
 (0)