我们都知道Hibernate可以支持多种数据库,这种支持是通过对于不同数据库,配置对应数据库的方言完成的。


在早期的Hibernate中,需要通过配置hibernate.dialect参数,指定当前使用的数据库方言。


对于需要同时支持多种数据库的产品来说,每切换一个数据库,就要重新配置以下dialect参数会显得很麻烦。


于是,DialectResolver工厂类就诞生了。


简单的说,DialectResolver以及其子类的作用,是根据数据库的MetaData,完成对于数据库类型的解析。


实际上,DialectResolver的作用还远不止这些,我们使用hibernate时,甚至编写属于自己的DialectResolver接口的实现类,完成我们自定义的dialect的创建。


 


DialectResolver类结构


DialectResolver使用我们熟知的Conposite、Template Method模式,类结构如下:



Hibernate源码解读--DialectResolver源码解读_oracle

 

上述类图涉及以下几个类:



  • DialectResolverSet:封装一个DialectResolver的集合,hibernate上下文最终使用这个类进行数据库方言解析
  • AbstractDialectResolver:抽象的DialectResolver类,作用是将调用DatabaseMetaData时可能出现的SQLException转换为以Hibernate为基类的运行时异常。
  • StandardDialectResolver:标准的DialectResolver,用来封装hibernate自带的方言解析流程
  • BasicDialectResolver:这个类没什么实际用途,目前代码中,没有对其的任何引用,应该是可以废弃的类


 


StandardDialectResolver


StandardDialectResolver类中,根据数据库的DatabaseMetaData,找到对应的数据库方言实现类,源码如下:



protected Dialect resolveDialectInternal(DatabaseMetaData metaData) throws SQLException {

String databaseName = metaData.getDatabaseProductName();

int databaseMajorVersion = metaData.getDatabaseMajorVersion();


if ( "CUBRID".equalsIgnoreCase( databaseName ) ) {

return new CUBRIDDialect();

}


if ( "HSQL Database Engine".equals( databaseName ) ) {

return new HSQLDialect();

}


if ( "H2".equals( databaseName ) ) {

return new H2Dialect();

}


if ( "MySQL".equals( databaseName ) ) {

return new MySQLDialect();

}


if ( "PostgreSQL".equals( databaseName ) ) {

final int databaseMinorVersion = metaData.getDatabaseMinorVersion();

if (databaseMajorVersion >= 8 && databaseMinorVersion >= 2) {

return new PostgreSQL82Dialect();

}

return new PostgreSQL81Dialect();

}


if ( "Apache Derby".equals( databaseName ) ) {

final int databaseMinorVersion = metaData.getDatabaseMinorVersion();

if ( databaseMajorVersion > 10 || ( databaseMajorVersion == 10 && databaseMinorVersion >= 7 ) ) {

return new DerbyTenSevenDialect();

}

else if ( databaseMajorVersion == 10 && databaseMinorVersion == 6 ) {

return new DerbyTenSixDialect();

}

else if ( databaseMajorVersion == 10 && databaseMinorVersion == 5 ) {

return new DerbyTenFiveDialect();

}

else {

return new DerbyDialect();

}

}


if ( "ingres".equalsIgnoreCase( databaseName ) ) {

switch( databaseMajorVersion ) {

case 9:

int databaseMinorVersion = metaData.getDatabaseMinorVersion();

if (databaseMinorVersion > 2) {

return new Ingres9Dialect();

}

return new IngresDialect();

case 10:

return new Ingres10Dialect();

default:

LOG.unknownIngresVersion(databaseMajorVersion);

}

return new IngresDialect();

}


if ( databaseName.startsWith( "Microsoft SQL Server" ) ) {

switch ( databaseMajorVersion ) {

case 8:

return new SQLServerDialect();

case 9:

return new SQLServer2005Dialect();

case 10:

return new SQLServer2008Dialect();

default:

LOG.unknownSqlServerVersion(databaseMajorVersion);

}

return new SQLServerDialect();

}


if ( "Sybase SQL Server".equals( databaseName ) || "Adaptive Server Enterprise".equals( databaseName ) ) {

return new SybaseASE15Dialect();

}


if ( databaseName.startsWith( "Adaptive Server Anywhere" ) ) {

return new SybaseAnywhereDialect();

}


if ( "Informix Dynamic Server".equals( databaseName ) ) {

return new InformixDialect();

}


if ( databaseName.equals("DB2 UDB for AS/400" ) ) {

return new DB2400Dialect();

}


if ( databaseName.startsWith( "DB2/" ) ) {

return new DB2Dialect();

}


if ( "Oracle".equals( databaseName ) ) {

switch ( databaseMajorVersion ) {

case 11:

return new Oracle10gDialect();

case 10:

return new Oracle10gDialect();

case 9:

return new Oracle9iDialect();

case 8:

return new Oracle8iDialect();

default:

LOG.unknownOracleVersion(databaseMajorVersion);

}

}


return null;

}

DialectResolverInitiator

DialectResovler最终由DialectResolverInitiator进行初始化。DialectResolverInitiator实现了BasicServiceInitiator接口,完成系统启动时必须的初始化工作。


如果需要配置自定义的DialectResovler对象,只要声明hibernate.dialect_resolvers参数,参数值是以逗号分隔的DialectResovler自定义实现的类名全称。


DialectResolverInitiator初始化并创建DialectResovler对象的源码如下:



private List<DialectResolver> determineResolvers(Map configurationValues, ServiceRegistryImplementor registry) {

final List<DialectResolver> resolvers = new ArrayList<DialectResolver>();


final String resolverImplNames = (String) configurationValues.get( AvailableSettings.DIALECT_RESOLVERS );


if ( StringHelper.isNotEmpty( resolverImplNames ) ) {

final ClassLoaderService classLoaderService = registry.getService( ClassLoaderService.class );

for ( String resolverImplName : StringHelper.split( ", \n\r\f\t", resolverImplNames ) ) {

try {

resolvers.add( (DialectResolver) classLoaderService.classForName( resolverImplName ).newInstance() );

}

catch (HibernateException e) {

throw e;

}

catch (Exception e) {

throw new ServiceException( "Unable to instantiate named dialect resolver [" + resolverImplName + "]", e );

}

}

}

/* 

* 不论是否配置AvailableSettings.DIALECT_RESOLVERS参数,均可以使用StandardDialectResolver进行方言解析

* 因为自定义的DialectResolver处于list的前面,所以自定义的DialectResolver优先级会比系统默认的高

*/

resolvers.add( new StandardDialectResolver() );

return resolvers;

}