`

技术总结:关于数据库数据的导出功能

阅读更多
解决的问题:要把原始数据库中的数据导出到其它的数据库表中去。

原始数据库可能是MYSQL, SQLSERVER或者其它的数据库,这些数据库的Schema是根据实体定义文件以及类型定义文件的。

数据要导入的数据库是HSQLDB,现有的ORM工具要求先建立对象到数据库结构的隐射,以及需要建立配置环境才能实现将对象隐射到数据库中的表结构中去。

因此,要解决数据导出导入问题,首先,要根据实体定义文件生成HSQL DB的Schema,执行建表操作,然后再把从原数据库中选择出来的实体插入到HSQL DB数据库中去。

因此,要解决的问题主要有两个:
1. 自动建立HSQL DB Schema
2. 自动将实体存储到HSQL DB

约束条件:
1. HSQL DB Schema和原数据库的Schema应该是类似的,能够兼容从原数据库中导入来的数据。数据域的名称是一样的。
2. 实体存储的时候可以借鉴ORM存储的方式。

解决技术:
1. Schema自动生成。新建HSQLDB.xml数据类型的映射文件,新建HSQL DB的Schema(create table)的语法,根据实体定义文件生成HSQL DB对应的Schema。

2. 实体存储。参考实体工具存储实体的方式。将实体看成JAVA BEAN,由于实体定义文件中定义了实体的域值。可以根据数据类型定义文件找到实体的域值所对应的JAVA TYPE。利用TYPE的nullSafeSet使得可以安全的设置PreparedStatement所对应的INSERT语句的参数。我最头疼的
	public void setString(PreparedStatement ps, int index, String value) throws SQLException{
		if(null!=value)
			ps.setString(index, value);
		else
			ps.setNull(index, Types.VARCHAR);
	}
        	public void setInteger(PreparedStatement ps, int index, Integer value) throws SQLException{
		if(null!=value)
			ps.setInt(index, value);
		else
			ps.setNull(index, Types.INTEGER);
	}

通过
property.nullSafeSet(ps, PropertyUtils.getProperty(element, fields[i].getName()), i+1);


调用Concrete Type中的nullSafeSet就解决了这个问题,真的是太爽了。

两个问题都解决了。最后看一下我的设计,自认为还比较优美:)
AbstractDataExporter是抽象的数据导出类,有两个Template模板方法,定义了数据导出的步骤。具体的数据导出类,只要实现抽象方法就可以了,具体类相当简单。

AbstractDataExporter借助SchemaGenerator来完成Schema生成操作:),顺便也完成了Drop Table语句的生成,以及INSERT 语句的生成。这些方法子类都不需要重写。

package ...
import ...

/**
 * 抽象的数据导出器。
 * 将原始数据库中的数据,导出到HSQLDB中的一个原始数据库中去。
 * @author wanzhigang
 *
 */
public abstract class AbstractDataExporter {

	protected String entityName; //数据库表所对应的实体名称	
	
	protected Connection connection;
	
	public AbstractDataExporter(Connection connection, String entityName){
		this.connection = connection;
		this.entityName = entityName;
	}
	
	/**
	 * 对应的HSQL DB表的Schema。
	 * @return
	 */
	public String getSchema(){
		return SchemaGenerator.instance.generateHSQLSchema(entityName);
	}
	
	/**
	 * 对应的HSQL DB表的Drop Table语句。
	 * @return
	 */
	public String getDropTableSQL(){
		return SchemaGenerator.instance.generateDropTableSQL(entityName);
	}
	
	/**
	 * 对应的HSQL DB表的Insert语句。
	 * @return
	 */
	public String getInsert() {
		return SchemaGenerator.instance.generateInsertSQL(entityName);
	}
	
	/**
	 * 将数据导出到HSQLDB中去。
	 * @throws DataExporterException
	 */
	protected void exportData2HSQLDBTemplate(Integer[] projectIds) throws DataExporterException{
		if(!createHSQLTable()) throw new DataExporterException("CreateHSQLTable Error");		
		List orginalDataList = importDataTemplate(projectIds);
		if(null==orginalDataList) throw new DataExporterException("ReadOrginalData Error");
		if(!insert2HSQLDB(orginalDataList)) throw new DataExporterException("InsertInto HSQLDB Error");
	}

	/**
	 * 将原始数据的实体插入到HSQLDB中去。
	 * @param orginalDataList
	 * @param insert
	 * @return 
	 */
	protected boolean insert2HSQLDB(List orginalDataList){
		try {
			connection.setAutoCommit(false);
			for (Iterator iter = orginalDataList.iterator(); iter.hasNext();) {
				BaseObject element = (BaseObject) iter.next();
				PreparedStatement ps = connection.prepareStatement(getInsert());
				if(!setInsertParameter(ps, element)) return false;
				if(-1 == ps.executeUpdate()){
					Debug.logError("Insert into HSQLDB error");
					return false;
				}
				ps.close();
			}
			connection.commit();
			return true;
		} catch (SQLException e) {
			Debug.logError("SQL Exception in connect to HSQL DB");
			try {
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			return false;
		}
	}

	/**
	 * 设置插入到HSQL DB数据库中INSERT语句对应的?的数值。
	 * @param ps 
	 * @param element 要插入的数据实体
	 */
	private boolean setInsertParameter(PreparedStatement ps, BaseObject element) {
		Entity entity =  (Entity) SchemaGenerator.instance.getEntityMap().get(entityName);
		Map fieldTypeDefMap = SchemaGenerator.instance.getFieldTypeDefMap();
		Field[] fields = entity.getField();
		for (int i = 0; i < fields.length; i++) {
			FieldTypeDef fieldTypeDef = (FieldTypeDef)fieldTypeDefMap.get(fields[i].getType());
			try {
				PropertyMetaData property = new PropertyMetaData(fields[i].getName(), 
						TypeFactory.getType(fieldTypeDef.getJavaType())
				);				
				property.nullSafeSet(ps, PropertyUtils.getProperty(element, fields[i].getName()), i+1);		
			} catch (TypeNotSupportException e) {
				Debug.logError("Type Not Support.");
				return false;
			}catch (JDBCException e) {
				Debug.logError("JDBC Exception.");
				return false;
			}catch (IllegalAccessException e) {
				Debug.logError("IllegalAccessException. ");
				return false;
			} catch (InvocationTargetException e) {
				Debug.logError("InvocationTargetException.");
				return false;
			} catch (NoSuchMethodException e) {
				Debug.logError("NoSuchMethodException.");
				return false;
			}		
		}
		return true;
	}

	/**
	 * 从原始数据库中读取原始数据。是根据HQL来构造导出语句,还是根据Entity工具的Criteria来构造导出语句,应该由用户来选择。
	 * @param projectIds 项目ID
	 * @param select Select语句
	 * @return 原始数据的实体列表
	 */
	protected List importDataTemplate(Integer[] projectIds){
		String hql = createSelectHQL(projectIds);
		HqlReturnBuilder hqlRb = new HqlReturnBuilder(hql);
		try {
			return RecordContainer.doSelect(new Criteria(), hqlRb);
		} catch (QueryException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 构造从原始数据库中取数据的SELECT语句。
	 * @param projectIds
	 * @return
	 */
	protected abstract String createSelectHQL(Integer[] projectIds);

	/**
	 * 创建HSQL表。
	 * @return
	 */
	protected boolean createHSQLTable(){
		PreparedStatement ps;
		try {
			ps = connection.prepareStatement(getDropTableSQL());
			ps.executeUpdate();
			ps.close();
			ps = connection.prepareStatement(getSchema());
			ps.executeUpdate();
			ps.close();
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}		
	}
}


下面是子类的示例:代码很简单吧:)

public class ProjectInfoExporter extends AbstractDataExporter {	
	public ProjectInfoExporter(Connection connection) {
		super(connection,"ProjectInfo");
	}
		
	@Override
	protected String createSelectHQL(Integer[] projectIds) {
		String selectHQL = "from ProjectInfo project where project.projectId = ";
		StringBuffer sb = new StringBuffer(selectHQL).append(projectIds[0]);
		if(projectIds.length == 1){
			return sb.toString();
		}else{
			for (int i = 1; i < projectIds.length; i++) {
				sb.append("or project.projectId = ").append(projectIds[i]);
			}
			return sb.toString();
		}
			
	}
}


SchemaGenerator:通过解析实体定义xml,以及数据类型定义xml来得到相关的Schema以及INSERT, DROP TABLE语句:)

package ...
import ...

/**
 * JOB:自动生成HSQL DB相关的Schema,
 * @author wanzhigang
 *
 */
public class SchemaGenerator {
	
	private Map entityMap;
	private Map fieldTypeDefMap;
	
	private final static String module = SchemaGenerator.class.getName();
	
	public static SchemaGenerator instance = new SchemaGenerator();
	
	private SchemaGenerator() {
		this.entityMap = initializeEntityMap();
		this.fieldTypeDefMap = initializeFieldTypeDefMap();
	}
			
	
	/**
	 * 取得Entity Map。
	 * @return
	 */
	private Map initializeEntityMap(){
		return XMLModelEntityReader.getModelReader().getEntityCache();
	}
	
	/**
	 * 取得FieldTypeDef Map.
	 * @return
	 */
	private Map initializeFieldTypeDefMap(){
		return XMLModelFieldTypeReader.getModelFieldTypeReader().getFieldTypeCache();
	}
	
	public Map getEntityMap() {
		return entityMap;
	}
	
	public Map getFieldTypeDefMap() {
		return fieldTypeDefMap;
	}
	
	
	/**
	 * @param entityName 实体名称,实体定义文件中写好的实体名称。
	 * @return 实体定义的HSQL Schema
	 */
	public String generateHSQLSchema(String entityName){
		if(null==entityMap.get(entityName)){
			Debug.logError("no corresponding entity.");
			return null;
		}else{
			return getCreateTableSQLForHSQLDB((Entity)entityMap.get(entityName));
		}
	}
	
	/**
	 * 生成Insert的SQL语句。
	 * @param entityName
	 * @return
	 */
	public String generateInsertSQL(String entityName){
		if(null == entityMap.get(entityName)){
			Debug.logError("no corresponding entity.");
			return null;
		}else{
			return getCreateInsertSQL((Entity)entityMap.get(entityName));
		}
	}
	
	public String generateDropTableSQL(String entityName){
		Entity entity = (Entity)entityMap.get(entityName);
		if(null == entity){
			Debug.logError("no corresponding entity.");
			return null;
		}
		StringBuffer sb = new StringBuffer("DROP TABLE ");
		sb.append(getTableName(entity));
		sb.append(" IF EXISTS;");
		return sb.toString();	
	}
	
	private String getCreateInsertSQL(Entity entity) {
		StringBuffer sb = new StringBuffer("INSERT INTO ");
		sb.append(getTableName(entity));
		sb.append(" VALUES (");
		for (int i = 0; i < entity.getField().length; i++) {
			sb.append("?,");
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(");");
		return sb.toString();
	}

	
	
	/**
	 * 给某个实体生成HSQLDB的表结构定义。
	 * @param entity
	 * @return
	 */
	private String getCreateTableSQLForHSQLDB(Entity entity) {
		StringBuffer sqlBuf = new StringBuffer("CREATE TABLE ");
		sqlBuf.append(getTableName(entity));
		sqlBuf.append(" (");
		Field[] fields = entity.getField();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			FieldTypeDef fieldTypeDef = (FieldTypeDef)fieldTypeDefMap.get(field.getType());
			if(null==fieldTypeDef){
				Debug.logError("Field type [" + field.getType() + "] not found for field [" + field.getName()
                               + "] of entity [" + entity.getEntityName() + "], not creating table.", module);
				return null;
			}
			sqlBuf.append(getColomName(field));
			sqlBuf.append(" ");
			sqlBuf.append(fieldTypeDef.getSqlType());
			if(null != field.getDefaultValue()){
				sqlBuf.append(" DEFAULT ");
				sqlBuf.append(field.getDefaultValue());
			}
			if(field.getIsPrimKey() || field.getNotNull() || field.getUnique()) {
				sqlBuf.append(" NOT NULL ");
			}else{
				sqlBuf.append(" NULL ");
			}
			sqlBuf.append(",");
		}
		sqlBuf.append(" PRIMARY KEY(");
		List primaryKeylist = getPrimaryKeyField(fields);
		int size = primaryKeylist.size();
		for (int i = 0; i < size; i++) {
			sqlBuf.append((String)primaryKeylist.get(i));
			if(i < size-1){
				sqlBuf.append(",");
			}
		}
		sqlBuf.append(")");
		sqlBuf.append(")");
		return sqlBuf.toString();
	}
	
	/**
	 * 取得所有是PrimaryKey的字段,记录下来
	 * @param fields
	 */
	private List getPrimaryKeyField(Field[] fields) {
		List primaryKey = new ArrayList();
		for (int i = 0; i < fields.length; i++) {
			if(fields[i].getIsPrimKey()){
				primaryKey.add(getColomName(fields[i]));
			}
		}
		return primaryKey;
	}

	
	public static String getColomName(Field field){
		return (field.getColName() == null) ? ModelUtil.javaNameToDbName(field.getName()): field.getColName();
	}
	
	public static String getTableName(Entity entity){
		return (entity.getTableName() == null)? ModelUtil.javaNameToDbName(entity.getEntityName()):entity.getTableName();
	}		
	
}


贴出主要的代码,和大家共飨之
分享到:
评论

相关推荐

    阿里的EasyExcel+Mysql方式实现数据库数据导出生成exce

    总结来说,阿里的EasyExcel结合SpringBoot和Mysql数据库,提供了一个完整的解决方案,实现了从数据库数据导出生成Excel文件,以及将Excel数据保存回数据库的功能。这种解决方案在处理大数据量时表现出色,具有低内存...

    数据库结构导出excel

    其强大的计算、图表和数据管理功能使得将数据库结构导出为Excel文件非常有用。用户可以对数据进行排序、过滤、计算,并创建图表,以便更好地理解和分析数据库的复杂性。 5. **数据库工具**:许多数据库管理工具(如...

    VB代码 从数据库快速导出数据到EXCEL

    - **SQL查询优化**:为了提高数据导出速度,应优化SQL查询语句,避免全表扫描,合理使用索引,减少不必要的计算和排序。 - **Excel文件格式**:除了`.xls`格式,现代Excel还支持`.xlsx`等格式,后者基于XML,具有更...

    数据库导出Word数据字典

    总结来说,“数据库导出Word数据字典”是一项实用的功能,它能帮助数据库管理和开发人员更有效地管理和共享数据库信息。通过导出到Word,不仅可以提高信息的可读性和可编辑性,还能简化协作和分享的过程。在实际工作...

    数据库数据导出excel表格

    在IT行业中,数据库数据导出至Excel表格是一项常见的任务,特别是在数据分析、报表生成以及数据交换等场景下。Java作为广泛使用的编程语言,提供了多种方法来实现这个功能。本篇文章将详细探讨如何使用Java进行...

    mysql数据库字典导出工具

    MySQL数据库字典导出工具是一种实用程序,专为数据库管理员和开发人员设计,用于方便地从MySQL数据库中提取和导出元数据。这个工具能够帮助用户生成SQL脚本或者HTML格式的文档,以便于理解、备份或分享数据库结构。...

    MySQL数据库表导出Word工具,生成数据库说明文档

    总结一下,"MySQL数据库表导出Word工具"是一个高效实用的解决方案,它通过ODBC和Word宏实现了数据库结构的自动化文档化。使用这个工具,你可以方便地创建和维护MySQL数据库的详细说明,提高团队的工作效率和沟通效果...

    数据库中保存文件导出工具

    数据库管理系统(DBMS)通常提供内置的导出功能,允许用户选择特定的数据表或查询结果,并将其转换为各种文件格式。这些格式可以包括CSV、XML、JSON、PDF等,以满足不同的应用场景。例如,.TXT文件通常用于简单的...

    数据库导入和导出

    本文主要介绍Oracle数据库的exp/imp工具,这两个工具分别用于数据导出和导入。 **一、导出工具 exp** Oracle的exp工具是一个命令行实用程序,用于将数据库中的数据和对象备份到一个二进制文件中。这个文件可以跨...

    Oracle9i&10g编程艺术:深入数据库体系结构.pdf

    - **DMP文件(EXP/IMP文件)**:用于数据导入导出。 - **数据泵文件**:介绍数据泵特性。 - **平面文件**:讨论了非结构化数据的存储方式。 4. **内存结构**:分析了Oracle数据库中的内存分配和管理机制。 - **...

    java操作数据库 导出excel

    在导出数据库数据到Excel时,通常会遍历结果集,为每一行创建一个新的行对象,然后将每列数据设置到对应的单元格。 总结来说,完成"java操作数据库导出excel"的任务,你需要掌握以下关键点: 1. 使用JDBC连接数据库...

    Oracle数据库导出导出Execl,txt,word等文档数据

    ### Oracle数据库数据导出至Excel、TXT、Word等文档详解 #### 一、概述 在日常的数据库管理和维护工作中,经常需要将Oracle数据库中的数据导出到其他格式的文件中,比如Excel、TXT或者Word等,以便于进一步的数据...

    使用poi从数据库导出excel表的示例

    在这里,我们结合这两个技术,通过Struts1控制器来调用POI功能,将数据库中的数据导出为Excel文件。 要实现这个功能,我们需要以下步骤: 1. **准备数据库连接**:首先,我们需要建立与数据库的连接。这通常通过...

    导出数据库的所有数据成YML文件

    标题 "导出数据库的所有数据成YML文件" 涉及到的是数据库管理和数据导出技术,特别是将数据库中的所有数据转换为YAML(YAML Ain't Markup Language)格式的文件。YAML是一种常用的数据序列化语言,常用于配置文件或...

    C#源代码 将数据库数据导出到excel中

    ### C#源代码将数据库数据导出到Excel中的知识点解析 #### 一、技术背景与需求分析 在软件开发过程中,经常会遇到需要将数据库中的数据导出为Excel文件的需求,以便于用户进行进一步的数据处理或者分析。对于.NET...

    SQL Server数据库导入导出技术

    SQL Server数据库导入导出技术是数据库管理员和开发人员在整合数据、迁移数据库或进行数据备份时常用的一种功能。SQL Server提供了多种方式进行数据导入和导出,以满足不同场景的需求。下面我们将详细介绍这些方法...

    ACCESS数据库二进制图片导出工具

    关于标签“图片导出”,这意味着该工具的核心功能是将Access数据库中存储的BLOB字段(通常是图片数据)导出为常见的图片格式,如JPEG、PNG或GIF。这可能涉及到读取数据库记录,解析BLOB数据,并将其转换成可识别的...

    JSP SERVLET 导出数据库内容到EXCEL

    总结来说,"JSP SERVLET 导出数据库内容到EXCEL"是一个典型的Java Web应用场景,结合了JSP的视图呈现、Servlet的业务处理和数据库操作,以及第三方库Apache POI的文件生成能力,为企业级应用提供了强大的数据导出...

    数据库应用技术:表数据的导入与导出.pptx

    数据库应用技术是信息技术领域中的重要组成部分,特别是在管理和处理大量数据时不可或缺。本节主要讨论了如何在MySQL数据库中实现表数据的导入与导出,这对于数据备份、迁移、分析和整合至关重要。 首先,我们关注...

    oracle 导出数据库中部分表

    其中,`exp`是较早版本的工具,而`expdp`则是基于Direct Path Load技术的现代工具,提供更高的性能和更多的功能选项。在本例中,我们将使用`expdp`来进行数据导出。 ### 命令行参数解析 在给定的部分内容中,...

Global site tag (gtag.js) - Google Analytics