package com.emr.annotation;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ProjectName:
 * @Description:
 * @Param 传输参数
 * @Return
 * @Author: 曾文和
 * @CreateDate: 2020/1/17 11:14
 * @UpdateUser: 曾文和
 * @UpdateDate: 2020/1/17 11:14
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class DynamicDataSourceContextHolder{
    private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
    /**
     * 设置默认数据源
     */
    public static  String DEFAULT_DS = "master";
    /**
     *用于轮训计数
     */
    private static int counter = 0;
    /*
     * 当使用ThreadLocal维护变量时，ThreadLocal为每个使用该变量的线程提供独立的变量副本，
     * 所以每一个线程都可以独立地改变自己的副本，而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> contextHolder = ThreadLocal.withInitial(() -> DataSourceKey.master.name());

    /**
     *用于在切换数据源时保证不会被其他线程修改
     */
    public static Lock lock = new ReentrantLock();

    /**
     * 设置数据源
     */
    public static void setDB(String dbType){
        contextHolder.set(dbType);
    }

    /**
     * 得到数据源
     *
     */
    public static String getDB(){
        return contextHolder.get();
    }

    /**
     * 使用主数据源
     */
    public static void useMasterDataSource() {
        contextHolder.set(DataSourceKey.master.name());
    }
    /**
     * 移除数据源
     */
    public static void removeDB(){
        contextHolder.remove();
    }
    /**
     * The constant slaveDataSourceKeys.
     */
    public static List<Object> slaveDataSourceKeys = new ArrayList<>();
    /**
     * 当使用只读数据源时通过轮循方式选择要使用的数据源
     */
    public static String getSlaveDB(){
        lock.lock();
        try {
            int datasourceKeyIndex = counter % slaveDataSourceKeys.size();
            counter++;
            return String.valueOf(slaveDataSourceKeys.get(datasourceKeyIndex));
        } catch (Exception e) {
            e.printStackTrace();
            return "master";
        } finally {
            lock.unlock();
        }
    }

}
