SpringBoot+Mybatis多数据源操作Presto

一,添加依赖

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

猜你喜欢

转载自www.cnblogs.com/oyjg/p/12566474.html