让Hibernate生成的DDL脚本自动增加注释

标签: hibernate ddl 脚本 | 发表时间:2013-10-08 08:05 | 作者:netv
出处:http://blog.csdn.net


我们知道可以通过Hibernate对象自动生成DDL建表语句,通过PowerDesigner工具可以反向工程生成数据字典,但是在生成的DDL中一直不能写上中文的注释,这就使我们生成的数据字典不具有可用性。

这个假期宅在家里调试代码,发现Hibernate的Dialect,Table,Column的映射中已经做了comment的处理,只是Hibernate团队认为这个功能的重要性太小,一直没有时间提供这个需求,于是就自己动手实现这个功能了,这可是使用我们的数据对象代码与数据字典文档同步的关键一环啊!

通过对Hibernate代码的跟踪发现了处理映射的逻辑是在代码AnnotationBinder中,我们不需要在运行期间处理comment,只是在用SchemaExport时处理就可以,于是简单的实现了此功能:

1. 增加一个注解 @Comment("这是表的说明,也可以是字段的说明"),适用在类名和属性名

2. 复制org.hibernate.cfg.AnnotationBuilder代码为org.hibernate.cfg.MyAnnotationBuilder,处理注解@Comment

3. 复制org.hibernate.cfg.Configuration为org.hibernate.cfg.MyConfiguration,将AnnotationBuilder的调用换成MyAnnotationBuilder

3. 实现SchemaExportTool类,传入MyConfiguration处理Hibernate对象的映射关系,并生成DDL

 

以上思路在基于Hibernate 4.2.3版本在MySql 5.1上测试成功,因为代码只是在开发期运行,不需要良好的结构和优化,所以只是简单实现了,需要此功能的朋友可以自己实现。

 

以下是处理结果示例:

@Entity
@Table(name = "AuditRecord_")
@Comment("系统审计表")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AuditRecord implements Serializable {

	private static final long serialVersionUID = 8844543936912679937L;
	@Id
	@GeneratedValue
	@Comment("ID主键")
	private Long id;
	@Comment("审计类型")
	@Column(length = 30)
	private String auditType;
	@Comment("操作人")
	@ManyToOne
	@JoinColumn(name = "userId")
	private Passport operator;
	// 操作简述
	@Comment("操作简述")
	@Column(length = 4000)
	private String description;
	@Comment("创建时间")
	private Date creationTime;
}


生成的DDL如下:

create table audit_record_ (
        id bigint not null auto_increment comment 'ID主键',
        audit_type varchar(30) comment '审计类型',
        creation_time datetime comment '创建时间',
        description longtext comment '操作简述',
        user_id bigint comment '操作人',
        primary key (id)
    ) comment='系统审计表';


 

主要代码片断如下:

 

import java.io.IOException;
import java.util.Properties;

import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;

import org.hibernate.MappingException;
import org.hibernate.cfg.MyConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

public class SchemaExportTool extends MyConfiguration {

	private static final long serialVersionUID = 1L;

	private static final String RESOURCE_PATTERN = "/**/*.class";

	private static final String PACKAGE_INFO_SUFFIX = ".package-info";

	private static final TypeFilter[] ENTITY_TYPE_FILTERS = new TypeFilter[] {
			new AnnotationTypeFilter(Entity.class, false),
			new AnnotationTypeFilter(Embeddable.class, false),
			new AnnotationTypeFilter(MappedSuperclass.class, false) };
	private final ResourcePatternResolver resourcePatternResolver;

	public SchemaExportTool() {
		this.resourcePatternResolver = ResourcePatternUtils
				.getResourcePatternResolver(new PathMatchingResourcePatternResolver());
	}

	public static void main(String[] args) {
		try {
			Properties p = new Properties();
			p.setProperty("hibernate.dialect",
					"org.hibernate.dialect.MySQLDialect");
			SchemaExportTool cfg = new SchemaExportTool();
			cfg.addProperties(p);
			cfg.setNamingStrategy(new ImprovedMyNamingStrategy());
			cfg.scanPackage("com.share.passport.domain",
					"com.share.authority.domain", "com.share.utils.domain");

			SchemaExport se = new SchemaExport(cfg);
			if (null != args && args.length > 1)
				if ("-f".equals(args[0]))
					se.setOutputFile(args[1]);
				else
					se.setOutputFile("create_table.sql");
			else
				se.setOutputFile("create_table.sql");
			se.setDelimiter(";");
			// se.drop(false, false);
			se.create(false, false);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private SchemaExportTool scanPackage(String... packagesToScan) {
		try {
			for (String pkg : packagesToScan) {
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
						+ ClassUtils.convertClassNameToResourcePath(pkg)
						+ RESOURCE_PATTERN;
				Resource[] resources = this.resourcePatternResolver
						.getResources(pattern);
				MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(
						this.resourcePatternResolver);
				for (Resource resource : resources) {
					if (resource.isReadable()) {
						MetadataReader reader = readerFactory
								.getMetadataReader(resource);
						String className = reader.getClassMetadata()
								.getClassName();
						if (matchesEntityTypeFilter(reader, readerFactory)) {
							addAnnotatedClass(this.resourcePatternResolver
									.getClassLoader().loadClass(className));
						} else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
							addPackage(className.substring(
									0,
									className.length()
											- PACKAGE_INFO_SUFFIX.length()));
						}
					}
				}
			}
			return this;
		} catch (IOException ex) {
			throw new MappingException(
					"Failed to scan classpath for unlisted classes", ex);
		} catch (ClassNotFoundException ex) {
			throw new MappingException(
					"Failed to load annotated classes from classpath", ex);
		}
	}

	/**
	 * Check whether any of the configured entity type filters matches the
	 * current class descriptor contained in the metadata reader.
	 */
	private boolean matchesEntityTypeFilter(MetadataReader reader,
			MetadataReaderFactory readerFactory) throws IOException {
		for (TypeFilter filter : ENTITY_TYPE_FILTERS) {
			if (filter.match(reader, readerFactory)) {
				return true;
			}
		}
		return false;
	}

}

/**
 * $Id:$
 */
package com.share.utils.hibernate;

import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.Ejb3Column;
import org.hibernate.mapping.PersistentClass;

import com.share.annotations.Comment;

public class CommentBinder {
    public static void bindTableComment(XClass clazzToProcess, PersistentClass persistentClass) {
        if (clazzToProcess.isAnnotationPresent(Comment.class)) {
            String tableComment = clazzToProcess.getAnnotation(Comment.class).value();
            persistentClass.getTable().setComment(tableComment);

        }
    }

    public static void bindColumnComment(XProperty property, Ejb3Column[] columns) {
        if (null != columns)

            if (property.isAnnotationPresent(Comment.class)) {
                String comment = property.getAnnotation(Comment.class).value();
                for (Ejb3Column column : columns) {
                    column.getMappingColumn().setComment(comment);
                }

            }
    }

    public static void bindColumnComment(XProperty property, Ejb3Column column) {
        if (null != column)
            if (property.isAnnotationPresent(Comment.class)) {
                String comment = property.getAnnotation(Comment.class).value();

                column.getMappingColumn().setComment(comment);

            }
    }
}
/**
 * $Id:$
 */
package com.share.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Comment {
    String value() default "";
}


作者:netv 发表于2013-10-8 0:05:01 原文链接
阅读:244 评论:0 查看评论

相关 [hibernate ddl 脚本] 推荐:

让Hibernate生成的DDL脚本自动增加注释

- - CSDN博客架构设计推荐文章
我们知道可以通过Hibernate对象自动生成DDL建表语句,通过PowerDesigner工具可以反向工程生成数据字典,但是在生成的DDL中一直不能写上中文的注释,这就使我们生成的数据字典不具有可用性. 这个假期宅在家里调试代码,发现Hibernate的Dialect,Table,Column的映射中已经做了comment的处理,只是Hibernate团队认为这个功能的重要性太小,一直没有时间提供这个需求,于是就自己动手实现这个功能了,这可是使用我们的数据对象代码与数据字典文档同步的关键一环啊.

mysql 5.6 online ddl 测试

- - CSDN博客数据库推荐文章
     在生产环境中,因为业务需求,改动mysql表结构,特别是数据量特别大的时候,几百万甚至几千万的数据,mysql online ddl操作非常让mysql dba揪心. 5.6版本支持online ddl.    为什么mysql ddl操作让dba揪心呢. 因为mysql ddl操作内部原理是这样的:.

Hibernate面试题

- - ITeye博客
什么是Hibernate的并发机制. Hibernate并发机制:. a、Hibernate的Session对象是非线程安全的,对于单个请求,单个会话,单个的工作单元(即单个事务,单个线程),它通常只使用一次,. 如果一个Session 实例允许共享的话,那些支持并发运行的,例如Http request,session beans将会导致出现资源争用.

Hibernate Lazy属性

- - 博客园_首页
  Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术. 这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录. 通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销. Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势.

Hibernate 缓存

- - ITeye博客
1数据缓存:(date caching) 是一种将数据暂时存于内存缓存去中的技术,缓存通常是影响系统性能的关键因素. 2.ORM的数据缓存策略有3中.   1.事务级缓存:  分为 数据库事务和 应用级事务,是基于Session的生命周期的实现,每个session都会在内部维持一个数据缓存, 随session的创建和消亡.

hibernate优化

- - 开源软件 - ITeye博客
原文 http://developer.51cto.com/art/200906/129539.htm. 文章分为十三个小块儿对Hibernate性能优化技巧进行总结性分析,分析如下:. 一、在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中,这缓存大太时会严重显示性能,所以在使用Hibernate处理大数据量的,可以使用session.

JPA & Hibernate 注解

- - CSDN博客编程语言推荐文章
必须,name为可选,对应数据库中一的个表 . 可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息 . name:可选,表示表的名称.默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名 . catalog:可选,表示Catalog名称,默认为Catalog(""). .

MySQL 5.6企业版支持全文索引和在线DDL

- - InfoQ cn
MySQL 5.6系列到达了一个新的里程碑,自此之后Oracle便能舒服地为它的付费客户发布更新的MySQL企业版了. 5.6版本中包含的企业版组件包括:. MySQL企业安全(PAM和Windows认证插件). 之前只有MySQL5.5的用户才能使用这些扩展. MySQL 5.6改进了安全功能,例如对关键配置文件和用户密码的加密方式,但是 对InnoDB的提升才是大新闻.

hibernate 大对象类型的hibernate映射

- - CSDN博客推荐文章
在 Java 中, java.lang.String 可用于表示长字符串(长度超过 255), 字节数组 byte[] 可用于存放图片或文件的二进制数据. 此外, 在 JDBC API 中还提供了 java.sql.Clob 和 java.sql.Blob 类型, 它们分别和标准 SQL 中的 CLOB 和 BLOB 类型对应.

JBoss发布Hibernate 4.0

- - InfoQ cn
近日, JBoss发布了流行的对象/关系(O/R)映射框架 Hibernate. Hibernate 4主要的新特性如下所示:. 引入了“Services”API. 提供了更棒的日志,支持 i18n与消息编码(通过JBoss Logging而非 slf4j). 为 OSGi支持做好了准备.