Sam*_*ser 4 java oracle hibernate spring-data-jpa
My company uses java 7 with hibernate 3 with spring 3 in one of it's legacy projects. All of the spring and hibernate configs are in xml files and they don't use annotations.
For some customers the database is oracle and for others it's db2.
In oracle we have problem when the data type is Date and we use java.util.date with time. The problem was located at the binding level when Hibernate prepared the query.
java.util.Date is converted to java.sql.Timestamp and finally bound to oracle.sql.TIMESTAMP.
Our column has oracle.sql.DATE type so there is an implicit conversion in Oracle to perform the query causing the index not to be used.
Our solution was using UserTypes in hibernate to convert java Date to Oracle Date in oracle databases.
But as I said we use xml config and I couldn't find xml config for @Type annotation when using hibernate with spring Jpa.
code for person class with logindate with Date type:
import org.hibernate.annotations.Type;
import javax.persistence.*;
import java.util.Date;
public class Person {
private Integer id;
private String fullName;
// @Type(type = "mypackage.OracleDate")
private Date loginDate;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public Date getLoginDate() {
return loginDate;
}
public void setLoginDate(Date loginDate) {
this.loginDate = loginDate;
}
}
Run Code Online (Sandbox Code Playgroud)
code for OracleDate UserType:
public class OracleDate implements UserType {
private static final int[] SQL_TYPES = new int[] {
Types.TIMESTAMP
};
@Override
public int[] sqlTypes() {
return SQL_TYPES;
}
@Override
public Class returnedClass() {
return Date.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (x == null || y == null) {
return false;
}
Date dtx = (Date) x;
Date dty = (Date) y;
return dtx.equals(dty);
}
@Override
public int hashCode(Object o) throws HibernateException {
return o.hashCode();
}
@Override
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
Object timestamp = StandardBasicTypes.TIMESTAMP.nullSafeGet(resultSet, names, null, owner);
if (resultSet.wasNull())
return null;
if (timestamp == null) {
return null;
}
Date ts = (Date) timestamp;
return ts;
}
@Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
if (value == null) {
StandardBasicTypes.TIMESTAMP.nullSafeSet(preparedStatement, null, index);
} else {
Date ldt = ((Date) value);
preparedStatement.setObject(index, new DATE(new Timestamp(ldt.getTime())));
}
}
Run Code Online (Sandbox Code Playgroud)
jpa bean:
<bean id="hostEntityManager"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="persistenceUnitManager" ref="persistenceUnitManager"></property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations" value="
classpath:PREPAID.CFG/DA.JPA/PERSISTENCE-ENTITIES/persistence.xml/>
<property name="persistenceUnitPostProcessors">
<bean class="mypackage.MergingPersistenceUnitPostProcessor" />
</property>
<property name="defaultDataSource" ref="dataSource"></property>
</bean>
Run Code Online (Sandbox Code Playgroud)
persistence.xml file:
<persistence version="2.0"
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 ">
<persistence-unit name="system_persistence_unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>TESTAPPLICATION/CFG/DA/JPA/PERSISTENCE-ENTITIES/person.xml</mapping-file>
<class>mypackage.Person</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="show_sql" value="true"/>
<property name="hibernate.archive.autodetection" value="class" />
</properties>
</persistence-unit>
Run Code Online (Sandbox Code Playgroud)
entitymapping file:
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
version="2.0">
<entity class="mypackage.Person">
<table name="Person" />
<named-query name="findLoginsByDate">
<query>select p from Person as p where p.loginDate >= :date </query>
</named-query>
<attributes>
<id name="id">
<column name="id" />
</id>
<basic name="fullName">
<column name="username" />
</basic>
<basic name="loginDate" >
<column name="loginDate" />
</basic>
</attributes>
</entity>
Run Code Online (Sandbox Code Playgroud)
At first I want know Is using usertype the best solution for handling my problem?
And what's the xml config for TypeDef and Type annotations?
首先,我想知道使用用户类型是解决我的问题的最佳解决方案吗?
在给定的情况下,当您将日期与时间存储在一起,并且别无选择,而是将其存储在DATE中时,可能就是这样。(请注意,类似这样的一些资源说使用TIMESTAMP应该可以,而且它甚至不会产生更大的索引。)
TypeDef和Type注释的xml配置是什么?
如果您不能在实体上使用注释,那么今天我只能看到以下可能性:
前提条件:您将必须将JPA XML映射迁移到Hibernate本机格式。
将此添加到您的共享映射XML:
<typedef class="com.company.OracleDate" name="OracleDate" />
Run Code Online (Sandbox Code Playgroud)
然后在实体映射XML中引用您的自定义类型:
<property name="loginDate" type="OracleDate" />
Run Code Online (Sandbox Code Playgroud)
前提条件:您将必须迁移到Hibernate 4.3或更高版本(请参阅兼容性列表),并将JPA 2.0配置文件迁移到2.1。
代替实现Hibenate的,UserType您需要实现JPA的AttributeConverter接口。这非常相似,这次您只需实现2种方法:DbType convertToDatabaseColumn(JavaType value)和JavaType convertToEntityAttribute(DbType value)。
之后,在实体映射XML中引用转换器:
<convert converter="com.company.OracleDateConverter" attribute-name="loginDate" />
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |