一,添加依賴
添加presto和mysql的依賴
<dependency> <groupId>com.facebook.presto</groupId> <artifactId>presto-jdbc</artifactId> <version>0.203</version> </dependency>
mysql的依賴就不貼了。
二,application.properties文件
三,多數據源配置
/** * aop數據源切換 * 自定義注解dataSource 默認數據源為mysql, @DataSource(PRESTO_DATA_SOURCE)在mapper接口加上此注解為presto */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) public @interface DataSource { String value() default DataSourceConstants.DEFAULT_DATA_SOURCE; }
@Configuration public class DataSourceConfig { Logger log = Logger.getLogger("dataSourceConfig"); @Autowired private DruidConfiguration defaultDataSource; @Autowired(required = false) private Interceptor[] interceptors; //presto數據源 @Bean(name = DataSourceConstants.PRESTO_DATA_SOURCE) @ConfigurationProperties(prefix = "presto.spring.datasource.marketing") public DataSource prestoDataSource() { return DataSourceBuilder.create().build(); } /** * 動態數據源: 通過AOP在不同數據源之間動態切換 * * @return */ @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 默認數據源 dynamicDataSource.setDefaultTargetDataSource(defaultDataSource.dataSource()); // 配置多數據源 Map<Object, Object> dsMap = new HashMap<>(); dsMap.put(DataSourceConstants.DEFAULT_DATA_SOURCE, defaultDataSource.dataSource()); dsMap.put(DataSourceConstants.PRESTO_DATA_SOURCE, prestoDataSource()); dynamicDataSource.setTargetDataSources(dsMap); return dynamicDataSource; } @Bean public SqlSessionFactoryBean sessionFactoryBean( @Value("${mybatis.mapper-locations}") String mapperLocations, @Value("${mybatis.configuration.map-underscore-to-camel-case}") boolean mapUnderscoreToCamelCase) throws IOException { System.out.println("mapperLocations--------->" + mapperLocations); System.out.println("map-underscore-to-camel-case--------->" + mapUnderscoreToCamelCase); log.info("mapperLocations--------->" + mapperLocations); log.info("map-underscore-to-camel-case--------->" + mapUnderscoreToCamelCase); SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(mapUnderscoreToCamelCase); String[] split = mapperLocations.split(","); PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); Resource[] resources1 = new Resource[0]; for (int i = 0; i < split.length; i++) { resources1 = (Resource[]) ArrayUtils.addAll(pathMatchingResourcePatternResolver.getResources(split[i]), resources1); } TypeHandler<?>[] typeHandlers = new TypeHandler[1]; typeHandlers[0] = new StringCodeEnumTypeHandler(DataSourceConfig.class); sqlSessionFactoryBean.setDataSource(dynamicDataSource()); sqlSessionFactoryBean.setMapperLocations(resources1); sqlSessionFactoryBean.setConfiguration(configuration); sqlSessionFactoryBean.setTypeHandlers(typeHandlers); if (interceptors != null) { sqlSessionFactoryBean.setPlugins(interceptors); } return sqlSessionFactoryBean; } /** * 注入 DataSourceTransactionManager 用於事務管理 */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
@Component public class DataSourceConfigurer extends AbstractBeanFactoryAwareAdvisingPostProcessor implements InitializingBean { /** * 切面攔截注入數據源 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { Pointcut pointcut = new AnnotationMatchingPointcut(null, DataSource.class); this.advisor = new DefaultPointcutAdvisor(pointcut,new DynamicDataSourceInterceptor()); } }
@Configuration public class DruidConfiguration { /** * 注冊一個StatViewServlet * @return */ @Bean public ServletRegistrationBean DruidStatViewServle2(){ //org.springframework.boot.context.embedded.ServletRegistrationBean提供類的進行注冊. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*"); //添加初始化參數:initParams //白名單: servletRegistrationBean.addInitParameter("allow",""); //IP黑名單 (存在共同時,deny優先於allow) : 如果滿足deny的話提示:Sorry, you are not permitted to view this page. servletRegistrationBean.addInitParameter("deny","192.168.1.73"); //登錄查看信息的賬號密碼. servletRegistrationBean.addInitParameter("loginUsername","admin"); servletRegistrationBean.addInitParameter("loginPassword","123456"); //是否能夠重置數據. servletRegistrationBean.addInitParameter("resetEnable","false"); return servletRegistrationBean; } /** * 注冊一個:filterRegistrationBean * @return */ @Bean public FilterRegistrationBean druidStatFilter2(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); //添加過濾規則. filterRegistrationBean.addUrlPatterns("/*"); //添加不需要忽略的格式信息. filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; } //配置數據庫的基本連接信息 @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource")//在application.properties中讀取配置信息注入到DruidDataSource里 public DataSource dataSource(){ DruidDataSource druidDataSource = DataSourceBuilder.create().type(DruidDataSource.class).build(); druidDataSource.setInitialSize(3);//初始化物理連接的數量 try { druidDataSource.addFilters("stat,wall");//stat是sql監控,wall是防火牆(如果不添加則監控無效),不能添加log4j不然會出錯 } catch (SQLException e) { e.printStackTrace(); } return druidDataSource; } }
public class DynamicDataSource extends AbstractRoutingDataSource { @Nullable @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDB(); } }
/** * 自定義數據源攔截器 */ public class DynamicDataSourceInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { Method method = methodInvocation.getMethod(); String dataSource = DataSourceConstants.DEFAULT_DATA_SOURCE; try { if(method.isAnnotationPresent(DataSource.class)){ DataSource annotation = method.getAnnotation(DataSource.class); dataSource = annotation.value(); } }catch (Exception e){ e.printStackTrace(); } //切換數據源 DataSourceContextHolder.setDB(dataSource); Object preceed = methodInvocation.proceed(); DataSourceContextHolder.clearDB(); return preceed; } }
/** * 常量 */ public class DataSourceConstants { public static final String DEFAULT_DATA_SOURCE = "defaultDataSource"; public static final String PRESTO_DATA_SOURCE = "prestoDataSource"; }
public class DataSourceContextHolder { /** * 默認數據源 */ private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); // 設置數據源名 public static void setDB(String dbType) { contextHolder.set(dbType); } // 獲取數據源名 public static String getDB() { return (contextHolder.get()); } // 清除數據源名 public static void clearDB() { contextHolder.remove(); } }
@MappedJdbcTypes({JdbcType.VARCHAR}) @MappedTypes({ICodeEnum.class}) public class StringCodeEnumTypeHandler<E extends ICodeEnum> extends BaseTypeHandler<E> { private Class<E> type; public StringCodeEnumTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; } @Override public void setNonNullParameter(PreparedStatement ps, int i, E e, JdbcType jdbcType) throws SQLException { if (jdbcType == null) { ps.setString(i, (String) e.getCode()); } else { ps.setObject(i, e.getCode(), jdbcType.TYPE_CODE); } } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { String s = rs.getString(columnName); return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type); } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String s = rs.getString(columnIndex); return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type); } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String s = cs.getString(columnIndex); return s == null ? null : CodeEnumAdapter.toCodeEnum(s, type); } }
public interface ICodeEnum<T> { T getCode(); }
public class CodeEnumAdapter { public static <T> T toCodeEnum(Object code, Class<T> type) { if (!type.isEnum()) { throw new IllegalArgumentException( String.format("type must be Enum,type : %s", type.getName())); } if (!ICodeEnum.class.isAssignableFrom(type)) { throw new IllegalArgumentException( String.format("type must be sub class by ICodeEnum,type : %s", type.getName())); } for (T t : type.getEnumConstants()) { ICodeEnum codeEnum = (ICodeEnum) t; if (Objects.equals(codeEnum.getCode(), code)) { return t; } } throw new IllegalArgumentException( "Cannot convert " + code + " to " + type.getSimpleName() + " by code."); } }
四,mapper配置
在mapper接口的 要使用presto數據源的接口加上自定義注解@DataSource
在xml文件select節點statementType屬性必須指定為STATEMENT
所以sql不能進行預編譯,即不能使用#{},只能采用${}的方式賦值