Spring JPA和Mybatis整合,首先添加必要的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
假設我們項目需要用到兩個庫os和ol,這兩個庫分别又有主從庫,分離讀寫,這是我的配置,僅作示例
@Configuration
@EnableJpaRepositories(basePackages = { "com.luckly.mall.repository.os" }, entityManagerFactoryRef = "entityManagerFactoryOs", transactionManagerRef = "transactionManagerOs")
@EntityScan(basePackages = { "com.luckly.mall.model" })
@MapperScan(basePackages = "com.luckly.mall.dao.os", sqlSessionFactoryRef = "sqlSessionFactoryOs", sqlSessionTemplateRef = "sqlSessionTemplateOs")
@EnableTransactionManagement
public class DataSourceConfigOs {
private static final Logger log = LoggerFactory.getLogger(DataSourceConfigOs.class);
@Autowired
private Environment env;
@Bean(name = "dbMasterOs")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.os.master")
public DataSource dbMaster() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dbSlaveOs")
@ConfigurationProperties(prefix = "spring.datasource.os.slave")
public DataSource dbSlave() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dataSourceOs")
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(dbMaster());
HashMap<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceKey.DB_MASTER, dbMaster());
dataSourceMap.put(DataSourceKey.DB_SLAVE, dbSlave());
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
}
}
entityManagerFactory,entityManager,sqlSessionFactory,sqlSessionTemplate,JdbcTemplate, transactionManager的代碼沒有貼出來,各位用的時候可以直接在下面加。
dbMaster,dbSlave分别是os庫的讀寫庫,ol庫類似,直接再寫一個DataSourceConfigOl,把os改成ol就好了,
主從資料源讀寫分離的話會設計到資料源切換,下面是具體代碼,主要有五個類
//
public enum DataSourceKey {
DB_MASTER,
DB_SLAVE
}
//
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {
DataSourceKey dataSourceKey() default DataSourceKey.DB_MASTER;
}
//
public class DynamicDataSourceHolder {
public static final ThreadLocal<DataSourceKey> holder;
public static void setDataSource(final DataSourceKey dataSourceKey) {
DynamicDataSourceHolder.holder.set(dataSourceKey);
}
public static DataSourceKey getDataSource() {
return DynamicDataSourceHolder.holder.get();
}
public static void clearDataSource() {
DynamicDataSourceHolder.holder.remove();
}
static {
holder = new ThreadLocal<DataSourceKey>();
}
}
//
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
//
@Aspect
@Component
@Order(-1)
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(targetDataSource)")
public void doBefore(JoinPoint joinPoint, TargetDataSource targetDataSource) {
DataSourceKey dataSourceKey = targetDataSource.dataSourceKey();
DynamicDataSourceHolder.setDataSource(dataSourceKey);
}
@After("@annotation(targetDataSource)")
public void doAfter(JoinPoint joinPoint, TargetDataSource targetDataSource) {
DataSourceKey dataSourceKey = targetDataSource.dataSourceKey();
DynamicDataSourceHolder.clearDataSource();
}
但這樣有個問題,必須在每個方法上添加@targetDataSource,是以稍微改一下
@Pointcut("execution(* com.luckly.mall.dao..*.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before(final JoinPoint joinPoint) {
final Object target = joinPoint.getTarget();
final String method = joinPoint.getSignature().getName();
final Class<?> classz = target.getClass();
final Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
try {
final Method m = classz.getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(TargetDataSource.class)) {
TargetDataSource targetDataSource = m.getAnnotation(TargetDataSource.class);
DynamicDataSourceHolder.setDataSource(targetDataSource.dataSourceKey());
logger.info("current datasource : {}", targetDataSource.dataSourceKey());
} else if (m.getAnnotation(TargetDataSource.class) == null) {
DynamicDataSourceHolder.setDataSource(DataSourceKey.DB_MASTER);
logger.info("current datasourcesd : {}", DataSourceKey.DB_MASTER);
}
} catch (Exception e) {
}
}
這樣有targetDataSource注解就走注解指定的,沒有就走主庫,當然在這裡你還可以通過切點,方法等進行比對或正則更細的處理,比如query開始的就走從庫,加個method.startsWith("query"),setDataSource(DataSourceKey.DB_SLAVE)