All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aliyun.openservices.ons.api.exactlyonce.manager.util.DBAccessUtil Maven / Gradle / Ivy

There is a newer version: 1.9.4.Final
Show newest version
package com.aliyun.openservices.ons.api.exactlyonce.manager.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.util.JdbcUtils;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.logging.InternalLogger;

import com.aliyun.openservices.ons.api.exactlyonce.TxConstant;
import com.aliyun.openservices.ons.api.exactlyonce.aop.model.MQTxContext;
import com.aliyun.openservices.ons.api.exactlyonce.aop.model.MQTxRecord;
import com.aliyun.openservices.ons.api.exactlyonce.datasource.DataSourceConfig;
import com.aliyun.openservices.ons.api.exactlyonce.manager.MetricService;
import com.aliyun.openservices.ons.api.exactlyonce.manager.datebase.AbstractDBAccessor;
import com.aliyun.openservices.ons.api.exactlyonce.manager.datebase.LoadRecordDo;
import com.aliyun.openservices.ons.api.exactlyonce.manager.datebase.MysqlAccessor;
import com.aliyun.openservices.ons.api.exactlyonce.manager.datebase.SqlServerAccessor;
import com.aliyun.openservices.ons.api.impl.util.ClientLoggerUtil;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;

/**
 * @author gongshi
 */
public class DBAccessUtil {
    public static final InternalLogger LOGGER = ClientLoggerUtil.getClientLogger();
    private final static ConcurrentHashMap dataSourcePool = new ConcurrentHashMap();
    private final static ConcurrentHashMap translatorMap = new ConcurrentHashMap();

    /**
     * Max active connection for internal datasource
     */
    private static final int INNER_DATASOURCE_MAX_ACTIVE = 2;

    /**
     * Init connection for internal datasource
     */
    private static final int INNER_DATASOURCE_INIT_SIZE = 1;

    /**
     * Max idle connection for internal datasource
     * 30000 is the minumum valid value for this parameter
     */
    private static final int INNER_EVICT_CONNECTION_MILLIS = 30 * 1000;

    private static AbstractDBAccessor getDBAccessor(DataSourceConfig config) throws Exception {
        if (config == null || StringUtils.isEmpty(config.getDriver())) {
            throw new Exception("datasource driver invalid " + config);
        }
        switch (DBType.parseTypeFromDriver(config.getDriver())) {
            case MYSQL:
                return MysqlAccessor.getInstance();
            case SQLSERVER:
                return SqlServerAccessor.getInstance();
            case ORACLE:
            case DB2:
            default:
                throw new Exception("unsupported db type" + config.getDriver());
        }
    }

    private static Connection getInternalConnection(String url, String user, String passwd, String driver) {
        String uniqKey = new StringBuilder(256)
            .append(url).append(TxConstant.DATASOURCE_KEY_SPLITOR)
            .append(user).append(TxConstant.DATASOURCE_KEY_SPLITOR)
            .append(passwd).append(TxConstant.DATASOURCE_KEY_SPLITOR)
            .append(driver).toString();
        DataSource dataSource = dataSourcePool.get(uniqKey);
        try {
            if (dataSource == null) {
                Map property = new HashMap();
                property.put(DruidDataSourceFactory.PROP_DRIVERCLASSNAME, driver);
                property.put(DruidDataSourceFactory.PROP_URL, url);
                property.put(DruidDataSourceFactory.PROP_USERNAME, user);
                property.put(DruidDataSourceFactory.PROP_PASSWORD, passwd);
                property.put(DruidDataSourceFactory.PROP_MAXACTIVE, String.valueOf(INNER_DATASOURCE_MAX_ACTIVE));
                property.put(DruidDataSourceFactory.PROP_INITIALSIZE, String.valueOf(INNER_DATASOURCE_INIT_SIZE));
                property.put(DruidDataSourceFactory.PROP_MINEVICTABLEIDLETIMEMILLIS, String.valueOf(INNER_EVICT_CONNECTION_MILLIS));
                dataSource = DruidDataSourceFactory.createDataSource(property);
                ((DruidDataSource)dataSource).setQueryTimeout(TxConstant.QUERY_TIMEOUT_SECOND);
                DataSource dataSourceOld = dataSourcePool.putIfAbsent(uniqKey, dataSource);
                if (dataSourceOld != null) {
                    ((DruidDataSource)dataSource).close();
                    dataSource = dataSourceOld;
                }
            }
            return dataSource.getConnection();
        } catch (Exception e) {
            LogUtil.error(LOGGER, "getInternalConnection fail, uniqKey:{}, err:{}", uniqKey, e.getMessage());
        }
        return null;
    }

    public static List queryAckedRecord(DataSourceConfig config, LoadRecordDo loadRecordDo) {
        List recordList = null;
        try {
            AbstractDBAccessor accessor = getDBAccessor(config);
            Connection connection = getInternalConnection(config.getUrl(), config.getUser(), config.getPasswd(),
                config.getDriver());
            if (accessor != null && connection != null) {
                long begin = System.currentTimeMillis();
                recordList = accessor.queryAckedRecord(connection, loadRecordDo);
                MetricService.getInstance().incQueryAcked(begin);
            }
        } catch (Exception e) {
            LogUtil.error(LOGGER, "query acked record fail, loadRecordDo:{}, err:{}", loadRecordDo, e.getMessage());
        }
        return recordList;
    }

    public static List queryExpiredRecord(DataSourceConfig config, Long timestamp, int count) {
        List recordList = null;
        try {
            AbstractDBAccessor accessor = getDBAccessor(config);
            Connection connection = getInternalConnection(config.getUrl(), config.getUser(), config.getPasswd(),
                config.getDriver());
            if (accessor != null & connection != null) {
                long begin = System.currentTimeMillis();
                recordList = accessor.queryExpiredRecord(connection, timestamp, count);
                MetricService.getInstance().incQueryExpired(begin);
            }
        } catch (Exception e) {
            LogUtil.error(LOGGER, "query acked record fail, timestamp:{}, count:{}, err:{}", timestamp, count, e.getMessage());
        }
        return recordList;
    }

    public static void insertTxRecord(Connection connection, DataSourceConfig config, MQTxRecord record) throws Exception {
        AbstractDBAccessor accessor = getDBAccessor(config);
        if (accessor == null || connection == null) {
            throw new Exception("access db fail, config:" + config);
        }
        long begin = System.currentTimeMillis();
        accessor.insertRecord(connection, record, false);
        MetricService.getInstance().incInsertRecord(begin);
    }

    public static boolean isRecordExist(MQTxContext context) {
        DataSourceConfig config = context.getDataSourceConfig();
        String messageId = context.getMessageId();
        try {
            AbstractDBAccessor accessor = getDBAccessor(config);
            Connection connection = getInternalConnection(config.getUrl(), config.getUser(), config.getPasswd(), config.getDriver());
            if (accessor != null && connection != null) {
                long begin = System.currentTimeMillis();
                Long id = accessor.queryRecordCountByMsgId(connection, config, messageId);
                MetricService.getInstance().incQueryMsgIdCount(begin);
                if (id != null) {
                    return true;
                }
            }
        } catch (Exception e) {
            LogUtil.error(LOGGER, "query isRecordExist fail, msgId:{}, err:{}", context.getMessageId(), e.getMessage());
        }
        return false;
    }

    public static void deleteRecordById(DataSourceConfig config, List msgIds) throws Exception {
        AbstractDBAccessor accessor = getDBAccessor(config);
        Connection connection = getInternalConnection(config.getUrl(), config.getUser(), config.getPasswd(), config.getDriver());
        if (accessor == null || connection == null) {
            throw new Exception("access db fail, config:" + config);
        }
        long begin = System.currentTimeMillis();
        accessor.deleteRecordById(connection, msgIds);
        MetricService.getInstance().incDeleteRecord(begin);
    }

    public static boolean isRecordDupException(MQTxContext context, Exception e) {
        if (!(e instanceof SQLException)) {
            return false;
        }
        boolean isDup = isDuplicateKeyException(context.getDataSourceConfig().getProductName(), (SQLException)e);
        if (isDup) {
            LogUtil.info(LOGGER, "exception is cased by record duped, context:{}, err:{}", context, e.getMessage());
        }
        return isDup;
    }

    private static boolean isDuplicateKeyException(String productName, SQLException e) {
        SQLExceptionTranslator sqlExceptionTranslator = translatorMap.get(productName);
        if (sqlExceptionTranslator == null) {
            sqlExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(productName);
            SQLExceptionTranslator oldTranslator = translatorMap.putIfAbsent(productName, sqlExceptionTranslator);
            if (oldTranslator != null) {
                sqlExceptionTranslator = oldTranslator;
            }
        }
        DataAccessException accessException = sqlExceptionTranslator.translate("", "", e);
        return accessException instanceof DuplicateKeyException;
    }


    public enum DBType {
        /**
         * MYSQL database
         */
        MYSQL(JdbcUtils.MYSQL, "com.mysql.jdbc.Driver"),

        /**
         * MS SQLSERVER database
         */
        SQLSERVER(JdbcUtils.SQL_SERVER, "com.microsoft.sqlserver.jdbc.SQLServerDriver"),

        /**
         * ORACLE database
         */
        ORACLE(JdbcUtils.ORACLE, "oracle.jdbc.driver.OracleDriver"),

        /**
         * IBM DB2 database
         */
        DB2(JdbcUtils.DB2, "COM.ibm.db2.jdbc.app.DB2Driver");

        private String dbType;
        private String driver;

        DBType(String dbType, String driver) {
            this.driver = driver;
        }
        public static DBType parseTypeFromDriver(String driver) {
            if (StringUtils.isEmpty(driver)) {
                return null;
            }
            for (DBType type : DBType.values()) {
                if (type.driver.equals(driver)) {
                    return type;
                }
            }
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy