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

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

原始数据库可能是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语句的参数。我最头疼的
[code]
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);
}
[/code]
通过
[code]property.nullSafeSet(ps, PropertyUtils.getProperty(element, fields[i].getName()), i+1);[/code]

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

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

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

[code]
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;
}
}
}
[/code]

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

[code]
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();
}

}
}
[/code]

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

[code]
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();
}

}
[/code]

贴出主要的代码,和大家共飨之 :D
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值