Статьи

JBoss 4.2.x Spring 3 JPA Учебное пособие по Hibernate

Потратив много часов на поиск в Интернете, пытаясь найти наиболее эффективный способ использования Spring, JPA и Hibenate для нескольких проектов, мы пришли к выводу о конфигурации, которая будет представлена ​​ниже. Интеграция Spring с JPA и Hibernate состоит из нескольких этапов:

  • Конфигурация контейнера Spring
  • Конфигурация уровня JPA ORM
  • Настройка Hibernate Second lvl cache (при необходимости)

Имейте в виду, что мы предполагаем, что работаем внутри контейнера J2EE в отношении источников данных, поэтому мы собираемся найти существующий источник данных из JNDI и использовать его. Файлы, которые мы собираемся настроить, описаны ниже:

  1. Файл spring.xml , который управляет контейнером Spring .
  2. Файл persistence.xml , который управляет слоем JPA ORM
  3. Второй файл кэша lvl, например treecache.xml для провайдера JBoss TreeCache (при необходимости)

Пример файла spring.xml представлен ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 xsi:schemaLocation="
>
 
 <context:component-scan base-package="com.mycomp.mypackage" />
 
 <task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
 
 <task:executor id="myExecutor" pool-size="5" />
 
 <task:scheduler id="myScheduler" pool-size="10" />
 
 <tx:annotation-driven />
 
 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="MyPersistenceUnit" />
 </bean>
 
 <bean id="transactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager">
  <property name="transactionManagerName" value="java:/TransactionManager" />
  <property name="userTransactionName" value="UserTransaction" />
 </bean>
 
</beans>

Несколько вещей, чтобы заметить здесь

  • Измените атрибут base-package контекста: тег component-scan на тот, который является базовым пакетом вашего проекта, чтобы проверять компоненты Spring (службы, DAO и т. Д.)
  • Измените атрибут значения свойства компонента persistentUnitName объекта entityManagerFactory на имя вашего постоянного модуля, как указано в файле persistence.xml.

Пример файла persistence.xml представлен ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 xsi:schemaLocation=
 version="1.0">
 
 <persistence-unit name="MyPersistenceUnit" transaction-type="JTA">
 
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <jta-data-source>java:/MyDataSource</jta-data-source>
  
  <properties>
   <property name="hibernate.dialect" 
     value="org.hibernate.dialect.HSQLDialect"/>
   <property name="hibernate.hbm2ddl.auto" value="update"/>
   <property name="hibernate.show_sql" value="false"/>
   <property name="hibernate.transaction.manager_lookup_class" 
     value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
 
   <!-- Uncomment below to use Hibernate second lvl cache -->
   <!--
   <property name="hibernate.cache.provider_class"
     value="org.hibernate.cache.TreeCacheProvider"/>
   <property name="hibernate.treecache.mbean.object_name"
     value="jboss.cache:service=TreeCache"/>
   <property name="hibernate.cache.use_second_level_cache"
     value="true"/>
   <property name="hibernate.cache.use_query_cache"
     value="true"/>
   <property name="hibernate.cache.use_structured_entries"
     value="true"/>
   -->
  </properties>
 
 </persistence-unit>
 
</persistence>

Несколько вещей, чтобы заметить здесь:

  • Имя единицы сохраняемости, здесь MyPersistenceUnit, должно соответствовать значению в файле spring.xml
  • Тип транзакции может иметь значения JTA или LOCAL, мы предполагаем, что мы развертываем внутри контейнера с поддержкой JTA, чтобы мы могли использовать глобальные транзакции (JTA), в любом другом случае вам следует использовать значение LOCAL
  • Как упоминалось выше, мы предполагаем, что мы внедряем в контейнер J2EE с источниками данных, объявленными в отдельных файлах и расположенными в JNDI, поэтому мы предписываем JPA использовать источник данных, найденный под конкретным именем JNDI, вы должны изменить это значение в соответствии с Ваше имя источника данных JNDI
  • Мы диктуем hibernate для использования гиперзвукового диалекта, вы должны изменить это значение в соответствии с вашим источником данных, например, для MySQL это значение должно быть org.hibernate.dialect.MySQLDialect (для механизма myISAM) или org.hibernate.dialect.MySQLInnoDBDialect (для Двигатель InnoDB)
  • Мы диктуем hibernate для поиска нашего менеджера транзакций JTA, например, если мы развертываем внутри JBoss, мы используем указанное значение, вы должны изменить это значение в соответствии с вашей средой
  • Если вы хотите включить Hibernate второй lvl кеш, просто раскомментируйте указанные директивы конфигурации

Пример второго файла кеша lvl (кеш дерева JBoss — treecache.xml) представлен ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<server>
 
 <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar" />
 
 <mbean code="org.jboss.cache.TreeCache" name="jboss.cache:service=TreeCache">
  <depends>jboss:service=Naming</depends>
  <depends>jboss:service=TransactionManager</depends>
  <attribute name="TransactionManagerLookupClass">
   org.jboss.cache.JBossTransactionManagerLookup</attribute>
  <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
  <attribute name="CacheMode">LOCAL</attribute>
  <attribute name="UseReplQueue">false</attribute>
  <attribute name="ReplQueueInterval">0</attribute>
  <attribute name="ReplQueueMaxElements">0</attribute>
  <attribute name="ClusterName">TreeCache-Cluster</attribute>
  <attribute name="ClusterConfig">
   <config>
    <UDP mcast_addr="228.1.2.3" mcast_port="48866" ip_ttl="64"
     ip_mcast="true" mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
     ucast_send_buf_size="150000" ucast_recv_buf_size="80000" loopback="false" />
    <PING timeout="2000" num_initial_members="3" up_thread="false"
     down_thread="false" />
    <MERGE2 min_interval="10000" max_interval="20000" />
    <FD_SOCK />
    <VERIFY_SUSPECT timeout="1500" up_thread="false"
     down_thread="false" />
    <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
     max_xmit_size="8192" up_thread="false" down_thread="false" />
    <UNICAST timeout="600,1200,2400" window_size="100"
     min_threshold="10" down_thread="false" />
    <pbcast.STABLE desired_avg_gossip="20000" up_thread="false"
     down_thread="false" />
    <FRAG frag_size="8192" down_thread="false" up_thread="false" />
    <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
     shun="true" print_local_addr="true" />
    <pbcast.STATE_TRANSFER up_thread="true"
     down_thread="true" />
   </config>
  </attribute>
  <attribute name="FetchInMemoryState">true</attribute>
  <attribute name="InitialStateRetrievalTimeout">20000</attribute>
  <attribute name="SyncReplTimeout">20000</attribute>
  <attribute name="LockAcquisitionTimeout">15000</attribute>
  <attribute name="EvictionPolicyClass"></attribute>
  <attribute name="UseMarshalling">false</attribute>
 </mbean>
 
</server>

Несколько вещей, чтобы заметить здесь

  • Обновите путь для загрузчика классов, чтобы найти два необходимых файла (jboss-cache.jar, jgroups.jar) для работы кеша дерева JBoss
  • Этот файл настраивает кэш дерева как службу JBoss MBean, поэтому его необходимо развернуть на сервере приложений JBoss, другие типы конфигурации выходят за рамки данного руководства и не будут обсуждаться далее. Для настройки кеша дерева JBoss в другой среде, пожалуйста, обратитесь к соответствующей документации

Вот и все, теперь позвольте мне представить пример DTO и DAO на основе конфигурации, описанной выше:

Первый класс DTO (EmployeeDTO)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.mycomp.myproject.dto;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name = "EMPLOYEE")
public class EmployeeDTO implements java.io.Serializable {
     
    private static final long serialVersionUID = 7440297955003302414L;
 
    @Id
    @Column(name="employee_id")
    private long employeeId;
     
    @Column(name="employee_name", nullable = false, length=30)
    private String employeeName;
     
    @Column(name="employee_surname", nullable = false, length=30)
    private String employeeSurname;
     
    @Column(name="job", length=50)
    private String job;
         
    public EmployeeDTO() {
    }
 
    public EmployeeDTO(int employeeId) {
        this.employeeId = employeeId;       
    }
 
    public EmployeeDTO(long employeeId, String employeeName, String employeeSurname,
            String job) {
        this.employeeId = employeeId;
        this.employeeName = employeeName;
        this.employeeSurname = employeeSurname;
        this.job = job;
    }
 
    public long getEmployeeId() {
        return employeeId;
    }
 
    public void setEmployeeId(long employeeId) {
        this.employeeId = employeeId;
    }
 
    public String getEmployeeName() {
        return employeeName;
    }
 
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
 
    public String getEmployeeSurname() {
        return employeeSurname;
    }
 
    public void setEmployeeSurname(String employeeSurname) {
        this.employeeSurname = employeeSurname;
    }
 
    public String getJob() {
        return job;
    }
 
    public void setJob(String job) {
        this.job = job;
    }
 
}

Ниже приведен класс DAO для доступа к данным Employee (EmployeeDTO).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.mycomp.myproject.dao;
 
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
 
import com.mycomp.myproject.dto.EmployeeDTO;
 
@Repository("employeeDAO")
public class EmployeeDAO extends JpaDAO<Long, EmployeeDTO> {
     
    @Autowired
    EntityManagerFactory entityManagerFactory;
     
    @PostConstruct
    public void init() {
        super.setEntityManagerFactory(entityManagerFactory);
    }
     
}

Как вы можете видеть, класс EmployeeDAO расширяет базовый класс DAO (JpaDao). Класс EmployeeDAO может содержать конкретные запросы, касающиеся объекта EmployeeDTO, но все операции CRUD могут быть обработаны из базового класса DAO (JpaDao), представленного ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package com.mycomp.myproject.dao;
 
import java.lang.reflect.ParameterizedType;
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
 
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;
 
public abstract class JpaDAO<K, E> extends JpaDaoSupport {
    protected Class<E> entityClass;
 
    @SuppressWarnings("unchecked")
    public JpaDAO() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass()
                .getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass
                .getActualTypeArguments()[1];
    }
 
    public void persist(E entity) {
        getJpaTemplate().persist(entity);
    }
 
    public void remove(E entity) {
        getJpaTemplate().remove(entity);
    }
     
    public E merge(E entity) {
        return getJpaTemplate().merge(entity);
    }
     
    public void refresh(E entity) {
        getJpaTemplate().refresh(entity);
    }
 
    public E findById(K id) {
        return getJpaTemplate().find(entityClass, id);
    }
     
    public E flush(E entity) {
        getJpaTemplate().flush();
        return entity;
    }
     
    @SuppressWarnings("unchecked")
    public List<E> findAll() {
        Object res = getJpaTemplate().execute(new JpaCallback() {
 
            public Object doInJpa(EntityManager em) throws PersistenceException {
                Query q = em.createQuery("SELECT h FROM " +
                        entityClass.getName() + " h");
                return q.getResultList();
            }
             
        });
         
        return (List<E>) res;
    }
 
    @SuppressWarnings("unchecked")
    public Integer removeAll() {
        return (Integer) getJpaTemplate().execute(new JpaCallback() {
 
            public Object doInJpa(EntityManager em) throws PersistenceException {
                Query q = em.createQuery("DELETE FROM " +
                        entityClass.getName() + " h");
                return q.executeUpdate();
            }
             
        });
    }
     
}

На этом уроке заканчивается вторая часть, где мы собираемся обсудить создание службы Spring здесь

Джастин