TopLink源代码分析 JPA中的如何实现多数据库平台的访问

[问题的由来]

一般来说,通用的商业产品都可以访问多数据库。TopLink也不例外,其中的JPA号称支持上十种数据库平台,而且还可以动态增加。那么具体的技术细节是怎么样呢?怎么实现的呢?

我们来看一看TopLink的源代码是如何实现的。

 

[源代码分析]

第一步:在登陆访问数据库时,首先执行下面的函数

public void loginAndDetectDatasource() throws DatabaseException {

    preConnectDatasource();

    Connection conn = null;

    try{

      conn = (Connection)getReadLogin().connectToDatasource(null);

        getLogin().setPlatformClassName(DBPlatformHelper.getDBPlatform(conn.getMetaData().getDatabaseProductName(), getSessionLog()));

        }catch (SQLException ex){

DatabaseException dbEx =  DatabaseException.errorRetrieveDbMetadataThroughJDBCConnection();

 // Typically exception would occur if user did not provide correct connection

// parameters. The root cause of exception should be propogated up

            dbEx.initCause(ex);

            throw dbEx;

        }finally{

            if (conn != null){

                try{

                    conn.close();

                }catch (SQLException ex){

                    DatabaseException dbEx =  DatabaseException.errorRetrieveDbMetadataThroughJDBCConnection();

   // Typically exception would occur if user did not provide correct connection

  // parameters. The root cause of exception should be propogated up

                    dbEx.initCause(ex);

                    throw dbEx;

                }

            }

        }

        connect();

        postConnectDatasource();

    }

 

第二步:在上面的函数中,有一个特别重要的函数,大家注意看,叫做DBPlatformHelper.getDBPlatform()

下面我们来看看这个函数到底做了什么?

public static String getDBPlatform(String vendorName, SessionLog logger) {

        initializeNameToVendorPlatform(logger);

        String detectedDbPlatform = null;

        if(vendorName != null) {

    detectedDbPlatform = matchVendorNameInProperties(vendorName, _nameToVendorPlatform, logger);

        }

        if (logger.shouldLog(SessionLog.FINE) ) {

     logger.log(SessionLog.FINE, "dbPlaformHelper_detectedVendorPlatform", detectedDbPlatform );

 // NOI18N

        }

        if (detectedDbPlatform == null) {

            if(logger.shouldLog(SessionLog.INFO)) {

                logger.log(SessionLog.INFO, "dbPlaformHelper_defaultingPlatform",  vendorName, DEFAULTPLATFORM); // NOI18N

            }

            detectedDbPlatform = DEFAULTPLATFORM;

        }

        return detectedDbPlatform;

    }

大家注意看,上面这个函数的第一行是:

initializeNameToVendorPlatform(logger);

这个函数是干什么的?是不是就是访问多数据库强大功能的秘密呢?我们再往下面看。

 

第三步:秘密原来在这里

private static Properties initializeNameToVendorPlatform(SessionLog logger) {

    synchronized(DBPlatformHelper.class) {

    if(_nameToVendorPlatform == null) {

                _nameToVendorPlatform = new Properties();

                try {

               loadFromResource(_nameToVendorPlatform, VENDOR_NAME_TO_PLATFORM_RESOURCE_NAME,                                           DBPlatformHelper.class.getClassLoader() );

                } catch (IOException e) {

                    logger.log(SessionLog.WARNING, "dbPlaformHelper_noMappingFound", VENDOR_NAME_TO_PLATFORM_RESOURCE_NAME);

                }

            }

        }

        return _nameToVendorPlatform;

    }

大家注意看,上面这个函数中,有一个很关键的一行代码

loadFromResource(_nameToVendorPlatform,VENDOR_NAME_TO_PLATFORM_RESOURCE_NAME, DBPlatformHelper.class.getClassLoader() );

这行代码干的事情就是动态的对应到不同的数据库平台。那么到底是怎么做到的呢?

这行代码中有一个变量,名字叫做[VENDOR_NAME_TO_PLATFORM_RESOURCE_NAME]

它的真实面貌如下:

private final static String VENDOR_NAME_TO_PLATFORM_RESOURCE_NAME =PROPERTY_PATH + "VendorNameToPlatformMapping.properties";  //NOI18N

关键问题出现了,原来它是最后找到了一个配置文件,通过它解决不同数据库的访问难题,那么最后我们来看看这个配置文件里面写着什么。

 

第四步:配置文件

#Property file containing mapping between vendor name and vendor platform

#The key of the property is in form of java regular expression.

#At runtime, vendor name obtained from DatabaseMetaData#getDatabaseProductName()

#is matched against the regular expresion to derive the DatabasePlaform we are

#running against.

SQL/ Anywhere=oracle.toplink.essentials.platform.database.SQLAnyWherePlatform

(?i)oracle.*=oracle.toplink.essentials.platform.database.oracle.OraclePlatform

(?i)(sybase.*)|(adaptive/ server/ enterprise.*)|(SQL/ Server)=oracle.toplink.essentials.platform.database.SybasePlatform

(?i)microsoft.*=oracle.toplink.essentials.platform.database.SQLServerPlatform

#Use JavaDBPlatform as the platform for Derby

(?i).*derby=oracle.toplink.essentials.platform.database.JavaDBPlatform

(?i).*db2.*=oracle.toplink.essentials.platform.database.DB2Platform

(?i)pointbase.*=oracle.toplink.essentials.platform.database.PointBasePlatform

(?i)mysql.*=oracle.toplink.essentials.platform.database.MySQL4Platform

(?i)informix.*=oracle.toplink.essentials.platform.database.InformixPlatform

(?i)postgresql.*=oracle.toplink.essentials.platform.database.PostgreSQLPlatform

(?i).*symfoware.*=oracle.toplink.essentials.platform.database.SymfowarePlatform

 

 

你可能感兴趣的:(TopLink源代码分析 JPA中的如何实现多数据库平台的访问)