天天看點

Hibernate5 ImplicitNamingStrategy與PhysicalNamingStrategy

Hibernate5中自定義實體類與資料庫命名規則的方法相比之前版本有較大改變,在hibernate5之前的版本實作NamingStrategy就可以實作自定義規則,hibernate5改為通過ImplicitNamingStrategy與PhysicalNamingStrategy實作。

關于ImplicitNamingStrategy與PhysicalNamingStrategy詳細的解釋可以看官方文檔,也可以參考其它博文,這裡不在詳述,參考博文:Hibernate入門之命名政策(naming strategy)詳解

簡單介紹一下ImplicitNamingStrategy與PhysicalNamingStrategy

ImplicitNamingStrategy:隐式規則,如果實體類沒有@Entity(name = "table_xxx")或@Column(name="column_xxx")等指定資料庫表名或列名的話,ImplicitNamingStrategy有效,如果在注解中指定名稱,則以注解為準。

PhysicalNamingStrategy:實體規則,不管有沒有@Entity(name = "table_xxx")或@Column(name="column_xxx")等注解命名,都要按自定義的PhysicalNamingStrategy規則映射資料庫名稱。

下面用示例來說明實際使用方法

需求一:為了統一命名規範,強制要求資料庫映射實體類屬性字段使用駝峰命名,資料庫字段使用下劃線_命名,而又不想麻煩在實體類每個屬性上都加上@Column(name="column_xxx")注解,而是沒有注解的根據屬性名自動映射資料庫字段,有注解的則使用注解的名稱映射,那麼應該使用ImplicitNamingStrategy。

hibernate已經提供了多個ImplicitNamingStrategy的實作,我們基于其中一個實作ImplicitNamingStrategyJpaCompliantImpl來做擴充

public class MyImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {

	private static final long serialVersionUID = 1l;

	@Override
	public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
		String name = source.getOwningPhysicalTableName() + "_"
				+ source.getAssociationOwningAttributePath().getProperty();
		return toIdentifier(name, source.getBuildingContext());
	}

	/**
	 * 重寫此方法實作,駝峰轉_
	 */
	@Override
	public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) {
		String name = transformAttributePath( source.getAttributePath() );
		name = addUnderscores(name);
		return toIdentifier( name, source.getBuildingContext() );
	}
	
	protected static String addUnderscores(String name) {
		StringBuilder buf = new StringBuilder( name.replace('.', '_') );
		for (int i=1; i<buf.length()-1; i++) {
			if (
				Character.isLowerCase( buf.charAt(i-1) ) &&
				Character.isUpperCase( buf.charAt(i) ) &&
				Character.isLowerCase( buf.charAt(i+1) )
			) {
				buf.insert(i++, '_');
			}
		}
		return buf.toString().toLowerCase(Locale.ROOT);
	}
}
           

隻需要重寫determineBasicColumnName(ImplicitBasicColumnNameSource source)方法即可實作改變列名命名規則

需求二:統一管理資料庫表的字首與字尾,如果在每個@Entity(name = "table_xxx")中都加上前字尾,會比較麻煩切不便于統一管理,那麼可以通過自定義PhysicalNamingStrategy實作

hibernate依然提供了多個PhysicalNamingStrategy的實作,我們基于其中的PhysicalNamingStrategyStandardImpl來實作需求

public class MyPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {
	private static final long serialVersionUID = 1l;
	
	/**
	 * 資料庫表字首
	 */
	private String prefix;
	
	/**
	 * 資料庫表字尾
	 */
	private String suffix;
	
	/**
	 * 資料庫表字首
	 */
	public String getPrefix() {
		return prefix;
	}

	/**
	 * 資料庫表字首
	 */
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	/**
	 * 資料庫表字尾
	 */
	public String getSuffix() {
		return suffix;
	}

	/**
	 * 資料庫表字尾
	 */
	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

    /**
	 * 重寫方法實作自動追加字首字尾
	 */
	@Override
	public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
		StringBuilder nameSB = new StringBuilder();
		if(!StringUtils.isEmpty(prefix)) {
			nameSB.append(prefix);
		}
		nameSB.append(name.getText());
		if(!StringUtils.isEmpty(suffix)) {
			nameSB.append(suffix);
		}
		
		return new Identifier(nameSB.toString(), name.isQuoted());
	}
}
           

重寫toPhysicalTableName方法即可實作對表名的規則定制

使用方法

<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.default_batch_fetch_size">16</prop>
			</props>
		</property>
		<property name="implicitNamingStrategy" ref="myImplicitNamingStrategy" />
		<property name="physicalNamingStrategy" ref="myPhysicalNamingStrategy" />
	</bean>

    <!-- 這裡是自定義的兩個類的bean -->
	<bean id="myImplicitNamingStrategy" 
		class="com.test.MyImplicitNamingStrategy"/>
	<bean id="myPhysicalNamingStrategy" 
		class="com.test.MyPhysicalNamingStrategy">
		<property name="prefix" value="u_"/>
		<property name="suffix" value="_s"/>
	</bean>