一,添加依赖
添加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不能进行预编译,即不能使用#{},只能采用${}的方式赋值