一口一口吃掉Hibernate(三)——Hibernate给表和字段设置前后缀及分隔符

2024-02-25 15:20

本文主要是介绍一口一口吃掉Hibernate(三)——Hibernate给表和字段设置前后缀及分隔符,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       在《一口一口吃掉Hibernate(一)——使用SchemaExport生成数据表》中介绍了如何生成数据表。但是这只是最基本的。Hibernate在生成或者操作数据库时,会受一些限制。比如一开始设计表的时候,直接写成了user(id,name,password,createTime)  这种格式的。但是客户后来要求表名称要以“t_”开头,字段名要以“stu_”开头,可以是一些数据库的关键字,单词之间以“_”隔开,方便他们维护.例如:T_User(stu_Id,stu_Name,stu_Create_Time)。


      对于上面的问题,常规的方法就是去修改Hibernate_cfg.xml中的表,为每个表添加“t_”,或者写table属性,字段也重新使用column属性来修改。如果你有100张表,每个表平均有10个字段,你还会去一个一个修改么?还有可能漏掉或者改错。最“可恶”的是,如果客户再让你改成其他的呢,是不是还要全部修改一次?


      有没有一种方法,不修改原先的配置,添加并配置一下表和字段的前后缀及分隔符等等,既可以完成呢??经过尝试,终于被我拿下了,现在拿出来与大家分享。


      针对上述问题,我主要用的是NamingStrategy接口。这个接口很有意思,可以作为业务类规范和数据库表规范的桥梁,它可以表和列的映射关系的转变和处理。例如一个数据对象User,对应数据库表是T_USER,如果所有映射关系都是这样的情况,可以使用NamingStrategy做为一个桥梁衔接,而不用再hbm.xml映射文件中指定class对应的物理table。


      先说一下Hibernate读取映射文件的简要过程:循环读取class标签,判断class标签的table属性值是否为null,若为null,则调用NamingStrategy接口的classToTableName方法将class值转换并处理(按命名策略NamingStrategy处理)的表名。若不为null,则说明设置了table,那么调用NamingStrategy接口的tableName方法获取处理过的表名。循环遍历property,判断property标签的column属性值是否为null,若为null,则首先调用propertyToColumnName方法,将属性值转化为列名,再调用logicalColumnName方法。若不为null,则直接调用NamingStrategy接口的logicalColumnName方法,再调用columnName方法进行处理(按命名策略NamingStrategy处理)。


      了解了上面说的这个过程,只要我们实现NamingStrategy这个接口,就可以随心所欲的修改表映射了。不多说了,直接上代码吧:

    【MyNamingStrategy】自定义的命名策略,可对表、字段进行统一处理。

package com.tgb.hibernate.neatlyDB;import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.util.StringHelper;/*** 数据库命名策略,可定制表、字段等的前后缀* * @author Longxuan* */
public class MyNamingStrategy implements NamingStrategy {/*** 数据库命名策略单一实例*/private static MyNamingStrategy instance = null;/*** 数据库配置信息类*/private static DatabaseConfiguration dbcfg = null;/*** 私有化构造方法*/private MyNamingStrategy() {}/*** 使用单利模式,获取数据库命名策略的唯一实例* * @return*/public static synchronized MyNamingStrategy getInstance() {// 默认读取hibernate.cfg.xml文件Configuration cfg = new Configuration().configure();return getInstance(cfg);}/*** 使用单利模式,获取数据库命名策略的唯一实例,同时使用默认Hibernate.cfg.xml更新命名策略信息* * @param cfg*            配置文件信息* @return*/public static synchronized MyNamingStrategy getInstance(Configuration cfg) {if (instance == null) {instance = new MyNamingStrategy();}MyNamingStrategy.dbcfg = new DatabaseConfiguration(cfg);return instance;}/*** 使用单利模式,获取数据库命名策略的唯一实例,同时更新命名策略信息* * @param cfg*            配置文件信息* @return*/public static synchronized MyNamingStrategy getInstance(DatabaseConfiguration dbcfg) {if (instance == null) {instance = new MyNamingStrategy();}MyNamingStrategy.dbcfg = dbcfg;return instance;}/*** 设置或更新数据库配置信息* * @param dbcfg*/public void setDBConfig(DatabaseConfiguration dbcfg) {MyNamingStrategy.dbcfg = dbcfg;}/*** 转化为物理表名* * @param className hbm.xml中的对应表的class值*/@Overridepublic String classToTableName(String className) {if(className == null ) return null;//改变大小写String str =UpdateStyle(className,dbcfg.getTableStyle().name());//添加前后缀str = addPrefixORStuffix(str, dbcfg.getTablePrefix(),dbcfg.getTableSuffix());//添加分隔符str = addSeparator(str,dbcfg.getTableSeparator());return str;}@Overridepublic String collectionTableName(String ownerEntity,String ownerEntityTable, String associatedEntity,String associatedEntityTable, String propertyName) {return null;}/*** 将读取到的列名传递过来进行加工处理,变为物理表的字段名* * @param columnName logicalColumnName方法读取到的列名*/@Overridepublic String columnName(String columnName) {//先调用logicalColumnName方法,拿到处理过的值,//再传递到该方法中,所以可以在这两个方法中任一选择修改。		//return columnName;if(columnName == null ) return null;//改变大小写String str =UpdateStyle(columnName,dbcfg.getColumnTyle().name());//添加前后缀str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());//添加分隔符str = addSeparator(str,dbcfg.getColumnSeparator());return str;}/*** 处理外键列名* */@Overridepublic String foreignKeyColumnName(String propertyName,String propertyEntityName, String propertyTableName,String referencedColumnName) {if(referencedColumnName == null ) return null;//改变大小写String str =UpdateStyle(referencedColumnName,dbcfg.getColumnTyle().name());//添加前后缀str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());//添加分隔符str = addSeparator(str,dbcfg.getColumnSeparator());return str;}/*** 关联键的名称*/@Overridepublic String joinKeyColumnName(String joinedColumn, String joinedTable) {if(joinedColumn == null ) return null;//改变大小写String str =UpdateStyle(joinedColumn,dbcfg.getColumnTyle().name());//添加前后缀str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());//添加分隔符str = addSeparator(str,dbcfg.getColumnSeparator());return str;}@Overridepublic String logicalCollectionColumnName(String columnName,String propertyName, String referencedColumn) {return null;}@Overridepublic String logicalCollectionTableName(String tableName,String ownerEntityTable, String associatedEntityTable,String propertyName) {return null;}/*** 处理逻辑列名* <b>若设置了column属性,会直接调用调用该方法</b>* * @param columnName	列名* @param propertyName	实体列名*/@Overridepublic String logicalColumnName(String columnName, String propertyName) {//name值对应propertyName,column值对应columnName//判断columnName是否设置,若设置了,则返回column值,否则返回propertyName值return columnName == null || columnName =="" ? propertyName:columnName;}/*** 处理逻辑列名* <b>若未设置column属性,则先调用该方法,再调用logicalColumnName方法</b>* * @param propertyName	实体列名*/@Overridepublic String propertyToColumnName(String propertyName) {if(propertyName == null ) return null;//改变大小写String str =UpdateStyle(propertyName,dbcfg.getColumnTyle().name());//添加前后缀str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());//添加分隔符str = addSeparator(str,dbcfg.getColumnSeparator());return str;}/*** 处理表名* <b>若设置了table属性,才会调用该方法</b>*/@Overridepublic String tableName(String tableName) {if(tableName == null ) return null;//改变大小写String str =UpdateStyle(tableName,dbcfg.getTableStyle().name());//添加前后缀str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getTablePrefix(),dbcfg.getTableSuffix());//添加分隔符str = addSeparator(str,dbcfg.getTableSeparator());return str;}/*** 单词分隔符* * @param name* @return*/private String addSeparator(String str, String flag) {StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));for (int i = 1; i < buf.length() - 1; i++) {if ('_' != buf.charAt(i - 1)&& Character.isUpperCase(buf.charAt(i))&& !Character.isUpperCase(buf.charAt(i + 1))) {// buf.insert(i++, '_');buf.insert(i++, flag);}}return buf.toString();}/*** 添加前后缀* * @param str*            字符串* @param prefix*            前缀* @param suffix*            后缀* @return*/private String addPrefixORStuffix(String str, String prefix, String suffix) {StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));buf.insert(buf.length(), suffix).insert(0, prefix);return buf.toString();}/*** 更新样式* @param str* @param style* @return*/private String UpdateStyle(String str, String style) {		if ("AU".equals(style)) {str = str.toUpperCase();} else if ("AL".equals(style)) {str = str.toLowerCase();} else if ("FU".equals(style)) {StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));String upper =buf.substring(0,1).toUpperCase();buf.delete(0, 1).insert(0, upper);str = buf.toString();} else if ("FL".equals(style)) {StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));String lower =buf.substring(0,1).toLowerCase();buf.delete(0, 1).insert(0, lower);str = buf.toString();}  else{}		return str;}}


【DatabaseConfiguration】数据库样式配置,包括前后缀、分隔符、大小写等

package com.tgb.hibernate.neatlyDB;import org.hibernate.cfg.Configuration;/*** 数据库模式配置* @author Longxuan**/
public final class DatabaseConfiguration {/*** 列名样式* AU-all upper case* AL-all lower case* FU-first upper case per word* FL-first lower case ,Other first letter upper case*/public static enum ColumnTyle {AU,AL,FU,FL;		}/*** 表名称样式* AU-all upper case* AL-all lower case* FU-first upper case per word* FL-first lower case ,Other first letter upper case*/public static enum TableStyle{AU,AL,FU,FL;}/*** 列名样式* AU-all upper case* AL-all lower case* FU-first upper case per word* FL-first lower case ,Other first letter upper case*/private ColumnTyle columnTyle = ColumnTyle.FL;/*** 表名称样式* AU-all upper case* AL-all lower case* FU-first upper case per word* FL-first lower case ,Other first letter upper case*/private TableStyle tableStyle = TableStyle.FU;/*** 表名称前缀*/private String tablePrefix = "";/*** 表名称后缀*/private String tableSuffix = "";/*** 表名称分隔符*/private String tableSeparator = "";/*** 列名前缀*/private String columnPrefix = "";/*** 列名后缀*/private String columnSuffix = "";/*** 列名分隔符*/private String columnSeparator = "";public ColumnTyle getColumnTyle() {return columnTyle;}public void setColumnTyle(ColumnTyle columnTyle) {this.columnTyle = columnTyle;}public TableStyle getTableStyle() {return tableStyle;}public void setTableStyle(TableStyle tableStyle) {this.tableStyle = tableStyle;}public String getTablePrefix() {return tablePrefix;}public void setTablePrefix(String tablePrefix) {this.tablePrefix = tablePrefix;}public String getTableSuffix() {return tableSuffix;}public void setTableSuffix(String tableSuffix) {this.tableSuffix = tableSuffix;}public String getTableSeparator() {return tableSeparator;}public void setTableSeparator(String tableSeparator) {this.tableSeparator = tableSeparator;}public String getColumnPrefix() {return columnPrefix;}public void setColumnPrefix(String columnPrefix) {this.columnPrefix = columnPrefix;}public String getColumnSuffix() {return columnSuffix;}public void setColumnSuffix(String columnSuffix) {this.columnSuffix = columnSuffix;}public String getColumnSeparator() {return columnSeparator;}public void setColumnSeparator(String columnSeparator) {this.columnSeparator = columnSeparator;}/*** 初始化,读取配置参数,默认读取Hibernate.cfg.xml* @param cfg*/public DatabaseConfiguration(){ReadConfig(new Configuration().configure()); }/*** 初始化,读取配置文件* @param cfg*/public DatabaseConfiguration(Configuration cfg){ReadConfig(cfg); }/*** 自动读取配置信息* @param cfg*/private void ReadConfig(Configuration cfg){tableStyle = cfg.getProperty("tablestyle")==""?TableStyle.FU:TableStyle.valueOf(cfg.getProperty("tablestyle"));tablePrefix = cfg.getProperty("tablePrefix");tableSuffix = cfg.getProperty("tablesuffix");tableSeparator = cfg.getProperty("tableseparator");columnTyle = cfg.getProperty("columntyle")==""?ColumnTyle.FL:ColumnTyle.valueOf(cfg.getProperty("columntyle"));columnPrefix = cfg.getProperty("columnPrefix");columnSuffix = cfg.getProperty("columnsuffix");columnSeparator = cfg.getProperty("columnseparator");}}


【hibernate.cfg.xml】设置数据库样式配置信息

<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory name="foo">		
<!-- name:		配置的名称style:		类型 枚举AU-all upper caseAL-all lower caseFU-first letter upper case per wordFL-first letter lower case ,Other first letters upper casebefix:		前缀suffix:		后缀separator:	分隔符--><property name="tablestyle">FU</property><property name="tablePrefix" >T_</property><property name="tablesuffix" ></property><property name="tableseparator" >_</property>		<property name="columntyle">FU</property><property name="columnPrefix">[stu_</property><property name="columnsuffix">]</property><property name="columnseparator">_</property><property name="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</property><property name="hibernate.show_sql">true</property><!-- 设置是否显示生成sql语句 --><property name="hibernate.format_sql">false</property><!-- 设置是否格式化sql语句--><mapping resource="com/bjpowernode/hibernate/User.hbm.xml" /></session-factory></hibernate-configuration>

【User.hbm.xml】 映射文件可以比较随意的修改或者设定了

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping><class name="com.bjpowernode.hibernate.User" table="Users"><id name="id" column="pid"><generator class="uuid" /></id><property name="name" column="userName"></property><property name="password" column="pwd"></property><property name="createTime"></property><property name="expireTime"></property></class>
</hibernate-mapping>

最后修改一下【ExportDB】,主要是修改必须先设置NamingStrategy,在调用configure方法

package com.bjpowernode.hibernate;import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;import com.tgb.hibernate.neatlyDB.DatabaseConfiguration;
import com.tgb.hibernate.neatlyDB.MyNamingStrategy;/*** 将hbm生成ddl* @author Longxuan**/
public class ExportDB {/*** @param args*/public static void main(String[] args) {//默认读取hibernate.cfg.xml文件,并按照命名策略修改表、字段的名称//Configuration cfg = new Configuration().configure(); //注意,必须先设置NamingStrategy,在调用configure方法Configuration cfg = new Configuration().setNamingStrategy(MyNamingStrategy.getInstance()).configure();SchemaExport export = new SchemaExport(cfg);//true 在控制台打印ddl语句,true 导入ddl语句到数据库,即可执行export.create(true, true);}}

      看一下结果图吧:表名,字段名都已经修改过了。



      上面演示的是生成数据表。在对数据库的增删改查时,只要同样设置NamingStrategy即可。

      为了大家更为方便的使用,已经做成jar包分享给大家了,点这里下载。



这篇关于一口一口吃掉Hibernate(三)——Hibernate给表和字段设置前后缀及分隔符的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745886

相关文章

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

Ubuntu中Nginx虚拟主机设置的项目实践

《Ubuntu中Nginx虚拟主机设置的项目实践》通过配置虚拟主机,可以在同一台服务器上运行多个独立的网站,本文主要介绍了Ubuntu中Nginx虚拟主机设置的项目实践,具有一定的参考价值,感兴趣的可... 目录简介安装 Nginx创建虚拟主机1. 创建网站目录2. 创建默认索引文件3. 配置 Nginx4

如何关闭 Mac 触发角功能或设置修饰键? mac电脑防止误触设置技巧

《如何关闭Mac触发角功能或设置修饰键?mac电脑防止误触设置技巧》从Windows换到iOS大半年来,触发角是我觉得值得吹爆的MacBook效率神器,成为一大说服理由,下面我们就来看看mac电... MAC 的「触发角」功能虽然提高了效率,但过于灵敏也让不少用户感到头疼。特别是在关键时刻,一不小心就可能触

Nginx配置系统服务&设置环境变量方式

《Nginx配置系统服务&设置环境变量方式》本文介绍了如何将Nginx配置为系统服务并设置环境变量,以便更方便地对Nginx进行操作,通过配置系统服务,可以使用系统命令来启动、停止或重新加载Nginx... 目录1.Nginx操作问题2.配置系统服android务3.设置环境变量总结1.Nginx操作问题

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

mybatis和mybatis-plus设置值为null不起作用问题及解决

《mybatis和mybatis-plus设置值为null不起作用问题及解决》Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查询时对空值的处理策略,通过配置不同的策略类型... 目录MyBATis-plusFieldStrategy作用FieldStrategy类型每种策略的作