我希望我的春季启动应用程序重新创建表格,并在每次运行我的应用程序时填写其内容。我正在使用带有create-drop
选项的Hibernate。我能够创建它并成功插入内容,但丢弃时会出现问题。我收到以下错误:
2015-11-21 14:17:42.694 ERROR 7028 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: drop table if exists gender
2015-11-21 14:17:42.694 ERROR 7028 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport : Cannot delete or update a parent row: a foreign key constraint fails
2015-11-21 14:17:42.757 ERROR 7028 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000389: Unsuccessful: drop table if exists profile
2015-11-21 14:17:42.757 ERROR 7028 --- [ost-startStop-1] org.hibernate.tool.hbm2ddl.SchemaExport : Cannot delete or update a parent row: a foreign key constraint fails
我知道发生这种情况是因为我在这两个表(gender
和profile
)之间存在关系。如何使用create-drop
成功删除整个表?
这是我的Gender
实体:
@Entity
public class Gender {
@Id
@Column(name = "gender_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "gender_name")
private String name;
}
这是我的Profile
实体:
@Entity
public class Profile {
@Id
@Column(name = "profile_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@ManyToOne(optional = false)
@JoinColumn(name = "gender_id", referencedColumnName = "gender_id")
private Gender gender;
}
答案 0 :(得分:1)
我解决了,但我的设置不同。我只在验证模式下使用hibernate并运行脚本来手动更新数据库。这些脚本由hibernate org.hibernate.tool.hbm2ddl.SchemaExport
生成。然后我获取生成的文件,在开头添加set foreign_key_checks = 0;
并设置foreign_key_checks = 1;在末尾。然后我注释掉了(在开头添加-
- 每一行都匹配模式alter table *. drop foreign key *.;
这是我的旧架构生成器,基于SchemaExport
:
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import javax.persistence.Entity;
import org.apache.commons.io.FileUtils;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.reflections.Reflections;
public class SchemaGenerator {
/** The configuration. */
private final Configuration cfg;
/**
* @param packageNames the package namesused
*/
public SchemaGenerator(final List<String> packageNames) throws Exception {
if (beanValidationInClasspath()) {
this.cfg = new ConfigurationWithBeanValidation();
} else {
this.cfg = new Configuration();
}
this.cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "create");
this.cfg.setProperty("javax.persistence.validation.mode", "ddl");
List<Class<?>> classes = getClasses(packageNames);
Collections.sort(classes, ClassComparator.INSTANCE);
for (Class<?> clazz : classes) {
this.cfg.addAnnotatedClass(clazz);
}
}
/**
* Method that actually creates the file.
*/
public void generate(final String fileName) {
this.cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
SchemaExport export = new SchemaExport(this.cfg);
export.setDelimiter(";");
export.setOutputFile(fileName);
export.execute(true, false, false, false);
try {
addAdditinalStatements(fileName);
} catch (IOException e) {
throw new RuntimeException("error will extending dll with addtional statement", e);
}
try {
addCommentDropConstraintStatements(fileName);
} catch (IOException e) {
throw new RuntimeException("error will extending dll by escaping drop foraign key relation ships", e);
}
}
private void addAdditinalStatements(final String fileName) throws IOException {
File outputFile = new File(fileName);
String original = FileUtils.readFileToString(outputFile, "utf-8");
String extended = "set foreign_key_checks = 1;\n"
+ original
+ "set foreign_key_checks = 0;\n";
FileUtils.writeStringToFile(outputFile, extended); }
void addCommentDropConstraintStatements(final String fileName) throws IOException {
File outputFile = new File(fileName);
List<String> original = FileUtils.readLines(outputFile, "utf-8");
String withComment = addCommentDropConstraintStatements(original);
FileUtils.writeStringToFile(outputFile, withComment);
}
private Pattern dropKeyStatementPattern = Pattern.compile("alter table .* drop foreign key [^;]*;");
String addCommentDropConstraintStatements(final List<String> original) {
StringBuilder shirnked = new StringBuilder();
for (int i = 0; i < original.size(); i++) {
if ((i + 2) < original.size()) {
String combined3Lines = original.get(i).trim() + " " + original.get(i + 1).trim() + " "
+ original.get(i + 2).trim();
if (dropKeyStatementPattern.matcher(combined3Lines).matches()) {
shirnked.append("-- " + combined3Lines + "\n");
i += 2; //skip the next two lines
} else {
shirnked.append(original.get(i) + "\n");
}
} else {
shirnked.append(original.get(i) + "\n");
}
}
return shirnked.toString();
}
/**
* Utility method used to fetch Class list based on a package name.
*
* @param packageNames (should be the package containing your annotated beans.
*
* @return the classes
*
* @throws Exception the exception
*/
private List<Class<?>> getClasses(final List<String> packageNames) throws Exception {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (String packageName : packageNames) {
System.out.println("scan:" + packageName);
Reflections reflections = new Reflections(packageName);
classes.addAll(reflections.getTypesAnnotatedWith(Entity.class));
}
return classes;
}
/**
* This filter accepts only java class files.
*/
public static class ClassFileFilter implements FileFilter {
/**
* The holy instance of class file filter.
*/
public static final ClassFileFilter INSTANCE = new ClassFileFilter();
@Override
public boolean accept(final File pathname) {
return pathname.isFile() && pathname.getName().endsWith(".class");
}
};
/**
* This filter accepts only java class files.
*/
public static class PackageDirectoryFilter implements FileFilter {
/**
* The holy instance of normal directory filter.
*/
public static final PackageDirectoryFilter INSTANCE = new PackageDirectoryFilter();
@Override
public boolean accept(final File pathname) {
return pathname.isDirectory() && !pathname.isHidden() && !pathname.getName().equalsIgnoreCase(".svn")
&& !pathname.getName().contains(".");
}
};
/**
* Check if Bean validation is in classpath.
*
* @return true, if NotNull class is found.
*/
private boolean beanValidationInClasspath() {
try {
Class.forName("javax.validation.constraints.NotNull");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
和错误修正类ConfigurationWithBeanValidation
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.MySQLInnoDBDialect;
/**
* Problem: Hibernate 4.x Schema Export tool does not pay attention to
* jsr303 annotations for ddl generation.
*
* This class fixes that problem. (use it instead of {@link Configuration}).
*
* This integration is usually performed by BeanValidationIntegrator.
* Unfortunately, that integration will only be activated upon
* initialization of the ServiceRegistry, which initializes
* DatasourceConnectionProviderImpl, which looks up the datasource,
* which requires a JNDI context ...
* We therefore reimplement the relevant parts of BeanValidatorIntegrator.
* Since that must occur after secondPassCompile(), which is invoked by
* Configuration.generateSchemaCreationScript, which is invoked by
* SchemaExport, some fancy subclassing is needed to invoke the integration
* at the right time.
*
* https://forum.hibernate.org/viewtopic.php?f=1&t=1014535
*/
public class ConfigurationWithBeanValidation extends Configuration {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -6277290406810542021L;
@Override
protected void secondPassCompile() throws MappingException {
super.secondPassCompile();
try {
// thank you, hibernate folks, for making this useful class package private ...
Method applyDDL = Class.forName("org.hibernate.cfg.beanvalidation.TypeSafeActivator").getMethod("applyDDL",
Collection.class,
Properties.class,
MySQLInnoDBDialect.class);
applyDDL.setAccessible(true);
applyDDL.invoke(null, classes.values(), getProperties(), MySQLInnoDBDialect.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
用法:
new SchemaGenerator(Arrays.asList("myPackage.com")).generate("ddl.sql");
org.reflections.Reflections
来自https://code.google.com/p/reflections/
图书馆(同时移至https://github.com/ronmamo/reflections
)
答案 1 :(得分:-2)
这是最简单的方法,但它不是一个很好的实践
SET FOREIGN_KEY_CHECKS=0
DROP TABLE IF EXISTS YourTableName
SET FOREIGN_KEY_CHECKS=1
这是你需要发送的MySql命令(我不知道你如何向MySql发送命令)