权威的 Hibernate 书籍“Java 持久性与 Hibernate”提到了这一点,关于 hibernate.hbm2ddl.auto 的 update 值(粗体是我的)
此配置属性的附加选项更新可以是
在开发过程中很有用:它启用了内置的 SchemaUpdate 工具,
这可以使模式演变更容易。如果启用,休眠读取
启动时的 JDBC 数据库元数据并创建新表和
通过将旧模式与当前映射进行比较来约束
元数据。 请注意,此功能取决于
由 JDBC 驱动程序提供的元数据,该区域包含许多驱动程序
缺乏。因此,在实践中,此功能不那么令人兴奋,并且
比听起来有用。
Hibernate 文档也建议here
SchemaUpdate 工具将使用
“增量”变化。 SchemaUpdate 依赖于 JDBC 元数据
API,因此不适用于所有 JDBC 驱动程序。
我尝试复制您的用例,发现我也遇到了这个问题令人惊讶。
我有一个这样的用户实体
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table( name = "usr" )
public class User {
@Id
@GeneratedValue
private Long id;
@Column( length = 40, unique = true )
private String name;
@Lob
@Column( length = 100000 )
private String text;
public long getId() {
return id;
}
public void setName( String name ) {
this.name = name;
}
public String getName() {
return name;
}
public String getText() {
return text;
}
public void setText( String text ) {
this.text = text;
}
}
而我的持久化xml是这样的
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="jpatest" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="root"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpadatabase"/>
<property name="hibernate.show-sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
如果我更改 hibernate.hbm2ddl.auto 的值来创建实体的文本属性并将其更改为此
.....
@Column( length = 255 )
private String text;
......
模式生成器在启动时生成以下 sql
DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text varchar(255), primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete
现在再次更改实体中的属性
.....
@Lob
@Column( length = 100000 )
private String text;
.......
现在生成以下正确的sql
DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text longtext, primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete
到目前为止一切顺利。
现在,如果我将值 hibernate.hbm2ddl.auto 更改为更新并以相同的顺序重复实体中的上述更改,则不会生成更新列 sql,尽管我已经从 varchar(255) 更新了文本列转长文
INFO TableMetadata:65 - table found: jpadatabase.usr
INFO TableMetadata:66 - columns: [id, text, name]
INFO TableMetadata:68 - foreign keys: []
INFO TableMetadata:69 - indexes: [name, primary]
DEBUG DefaultIdentifierGeneratorFactory:90 - Setting dialect [org.hibernate.dialect.MySQL5InnoDBDialect]
INFO SchemaUpdate:217 - schema update complete
但是,如果我使用更新和而不是修改属性,我添加另一个属性位置,然后再次生成正确的 sql
DEBUG SchemaUpdate:203 - alter table usr add column location varchar(255)
INFO SchemaUpdate:217 - schema update complete
所以本质上创建(首先删除表然后重新创建)可以正常工作,但是如果属性元数据有修改,则更新不会。
在我看来,增量更新的驱动程序支持问题似乎在这里发挥了作用。
同样直观地如果我想到这一点,那么支持更新列的数据类型是没有意义的。如果修改后的列数据类型是早期数据类型的缩小版本,现有数据会发生什么情况。