Я использую Hibernate 3.2.5 и Hibernate Annotations 3.3.1.GA в качестве поставщика JPA в приложении для загрузки данных. Я настроил Hibernate на использование C3P0 для пула соединений.
Моя база данных: Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 — 64-битная версия
Поскольку для 11g нет встроенного диалекта гибернации, я настроил его для использования
org.hibernate.dialect.Oracle10gDialect
Драйвер JDBC: драйвер Oracle JDBC, версия: 11.2.0.1.0
Приложение загружает некоторые журналы производительности транзакций из мейнфрейма в базу данных Oracle для последующего анализа и составления отчетов. По сути, это пакетное задание, которое отслеживает папку и ждет новый файл, затем считывает его и вставляет в базу данных (в среднем около 4,5 миллионов строк вставляется в день), поэтому я выбрал Hibernate из-за его способности использовать пакетные вставки JDBC, которые после некоторого сравнительного тестирования не так хорошо работает в EclipseLink. Файлы имеют проприетарный двоичный формат, поэтому я не могу использовать более простые инструменты, такие как импорт CSV и т. д.
Первоначально я разработал приложение для использования с MySQL на своей рабочей станции, так как изначально оно предназначалось для однократной задачи анализа, но теперь я хочу перенести его на корпоративную платформу Oracle RAC, поскольку оказалось полезным продолжать импортировать данные и сохранять их. на пару месяцев для использования мной и несколькими другими аналитиками. Я попросил администратора базы данных настроить таблицы и скорректировать классы Entity, чтобы отразить некоторые незначительные изменения в именах полей и типах данных, а также изменить драйвер, сведения о соединении и т. д., но я столкнулся с некоторыми проблемами с генерацией первичного ключа.
Есть несколько таблиц (основная таблица данных с несколькими таблицами, в которых хранятся различные вспомогательные типы, например, тип транзакции, коды пользователей и т. д.). У каждого есть уникальный (первичный) столбец идентификатора, который автоматически генерируется с использованием последовательности и триггера перед обновлением.
Администратор базы данных настроил последовательности так, чтобы созданные ими пользователи не могли просматривать их.
Использование типов сгенерированных значений JPA (javax.annotations) не будет работать в любом случае.
eg:
@GeneratedValue(strategy = GenerationType.AUTO)
Это дает SQL:
select hibernate_sequence.nextval from dual
Какие драйверы Oracle выдают исключение с ошибкой:
25/11/2009 11:57:23 AM org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 2289, SQLState: 42000
25/11/2009 11:57:23 AM org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: ORA-02289: sequence does not exist
Узнав, что я провел некоторое исследование и нашел варианты использования расширений аннотаций Hibernate JPA «GenericGenerator» со стратегией «выбора» (http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping.html#mapping-declaration-id-generator)
eg
@GeneratedValue(generator="id_anEntity")
@GenericGenerator(name = "id_anEntity",
strategy = "select")
Однако, когда я использую это, я обнаруживаю, что Hibernate зависает во время создания EntityManagerFactory. Кажется, что он прошел мимо создания свойств, построения именованных запросов, подключения к серверу, а затем зависает на:
25/11/2009 1:40:50 PM org.hibernate.impl.SessionFactoryImpl <init>
INFO: building session factory
и не возвращается.
Я обнаружил, что то же самое произошло, когда я не указал диалект в файле persistence.xml.
Он отлично работает, если я использую стратегию «приращения», хотя это означает, что последовательности затем разбиваются, поскольку значение было увеличено без увеличения последовательности, что далеко от идеала.
«Собственная» стратегия дает тот же результат, что и использование GenerationType.AUTO (ORA-02289: последовательность не существует).
Я не уверен, связано ли это с тем, что я использую неправильную стратегию генерации ключей, или с ошибкой в моей конфигурации, или с ошибкой.
Мы очень ценим любую помощь в том, чтобы заставить работать стратегию «выбрать» или лучшую альтернативу. Я потенциально мог бы вернуться к использованию чистого JDBC с подготовленными операторами и т. д., но это имеет тенденцию становиться немного запутанным, и я предпочитаю подход JPA.
Еще немного информации:
Свойства Persistence.xml:
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="1800"/>
<property name="hibernate.c3p0.max_statements" value="100000"/>
<property name="hibernate.jdbc.use_get_generated_keys" value="true"/>
<property name="hibernate.cache.use_query_cache" value="false"/>
<property name="hibernate.cache.use_second_level_cache" value="false"/>
<property name="hibernate.order_inserts" value="true"/>
<property name="hibernate.order_updates" value="true"/>
<property name="hibernate.connection.username" value="myusername"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.connection.password" value="mypassword"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP) (HOST = myoracleserver) (PORT = 1521))
(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = myservicename))
)"/>
<property name="hibernate.jdbc.batch_size" value = "100000" />
Пример объявления поля ID в одном из классов сущностей с использованием аннотаций:
@Entity
@Table(name = "myentity",
catalog = "",
schema = "mydb")
public class myEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@GeneratedValue(generator="id_anEntity")
@GenericGenerator(name = "id_anEntity",
strategy = "select")
@Column(name = "MYENTITYID",
nullable = false)
private Integer myEntityID;
//... other column mappings
public Integer getMyEntityID() {
return myEntityID;
}
public void setMyEntityID(Integer myEntityID) {
this. myEntityID = myEntityID;
}
//... other getters & setters
}