我使用的是使用Spring配置的Hibernate 4。我有一个简单的User类,它的密码属性用@Type annotation:进行了注释
@Entity
@Table(name = "Users")
public class User extends BaseEntity
{
@Column(name = "UserName", unique = true, length = 31)
@NotBlank(message = "User Name is required.")
@Size(min = 3, max = 31, message = "User Name must be between 3 and 31 characters in length.")
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
@Column(name = "Password", length = 511)
@Type(type = "org.jasypt.hibernate4.type.EncryptedStringType", parameters = { @Parameter(name = "encryptorRegisteredName", value = "passwordEncryptor") })
@NotBlank(message = "Password is required")
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}
我正在运行一个集成测试,它使用HSQLDB作为存储引擎。测试只是创建一个User实例,并将其持久化
问题是,当用户被持久化时,密码列完全被排除在生成的SQL:之外
2829 [main] DEBUG org.hibernate.SQL - insert into Users (Id, anonymous, Email, FirstName, LastName, Password, UserName) values (default, ?, ?, ?, ?, ?, ?)
2829 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BOOLEAN] - false
2830 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - admin@testing.com
2830 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [3] as [VARCHAR] - admin
2830 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [VARCHAR] - admin
3069 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [VARCHAR] - administrator
正如您所看到的,insert语句有6个占位符,而Hibernate只绑定了其中的5个参数。看看索引数字,你可以看到它正在跳过索引#5。
这是我的春季配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:ExampleTest" />
<property name="initialSize" value="1" />
<property name="maxActive" value="5" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.my.entities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<bean id="hibernateStringEncryptor"
class="org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor">
<property name="registeredName">
<value>passwordEncryptor</value>
</property>
<property name="algorithm">
<value>PBEWithMD5AndTripleDES</value>
</property>
<property name="password">
<value>MY_PASSWORD_HERE</value>
</property>
</bean>
是我做错了什么,还是这是个bug?
编辑:似乎发生的并不是该列被跳过,而是被添加到insert语句中,只是没有被注销(令人讨厌)。真正的错误是生成的Password列具有错误的列长度(24而不是511)。
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.error.Error.error(Unknown Source)
我将调试hibernate代码并弄清楚发生了什么。
调试Hibernate代码后,发现我的@Size验证约束覆盖了@Column(length=511)注释。因此,生成的列的长度为24,而不是511。
这可能是Hibernate中的一个错误,因为JPA规范(根据这个答案)说@Column注释应该用于DDL,而@Size属性应该仅用于验证。至少,@Column应该覆盖人们认为的@Size。尤其是在这种情况下,我使用的UserType会更改插入的字符串的大小。
最后,为了运行集成测试,我所做的只是告诉hibernate忽略集成测试项目中模式生成的验证,方法是添加"hibernate.validator.apply_to_ddl"属性:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.myentities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.globally_quoted_identifiers">true</prop>
<!-- THIS LINE HERE -->
<prop key="hibernate.validator.apply_to_ddl">false</prop>
</props>
</property>
</bean>