В этой статье показано, как быстро включить Ehcache в приложениях Openxava и, таким образом, повысить производительность.
При просмотре объекта и его графика загружаются отношения. Добавление кэша второго уровня ускоряет поиск связанных элементов, поскольку уже загруженные элементы извлекаются из кэша, а не из базы данных.
В конце концов, эта страница объясняет, как minuteproject относится к этому аспекту, выполняя свое обещание: ничего не писать.
В качестве примера мы возьмем витрину Lazuly.
Интеграция Openxava-Ehcache
В Openxava вы описываете свою модель в виде POJO, аннотированного Java. Аннотации исходят из стандартного ORM JPA2 и специфичных для Openxava.
Но ничто не мешает вам добавлять других. Это то, что делается для добавления кеширования. Есть также несколько конфигураций для включения кэширования.
Список действий
- Добавьте файл конфигурации ehcache.xml в корень ваших источников
- Измените файл persistence.xml, чтобы включить кэш второго уровня
- Добавить аннотацию кеширования (вместе с JPA2)
Замечание:
Openxava поставляется с ehcache.jar, поэтому нет необходимости добавлять зависимость.
Подробные действия
Добавить ehcache.xml
В / persistence поместите файл ehcache.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
<ehcache> <defaultCache maxElementsInMemory= "1000" eternal= "false" timeToIdleSeconds= "300" timeToLiveSeconds= "300" overflowToDisk= "false" diskPersistent= "false" diskExpiryThreadIntervalSeconds= "300" memoryStoreEvictionPolicy= "LRU" /> <cache name= "your.domain.object" maxElementsInMemory= "5000" eternal= "false" timeToIdleSeconds= "300" timeToLiveSeconds= "600" overflowToDisk= "false" /> </ehcache> |
Изменить файл persistence.xml
Файл Persistence.xml содержит информацию, относящуюся к единице сохранения, такую как информация о пуле соединений,
класс или конфигурация для загрузки. ‘persistence.xml’ находится в / persistence / META-INF
Мы добавим свойства для кеша второго уровня.
1
2
3
4
5
6
7
8
9
|
< properties > < property name = "hibernate.dialect" value = "org.hibernate.dialect.MySQLDialect" /> < property name = "hibernate.cache.provider_class" value = "net.sf.ehcache.hibernate.SingletonEhCacheProvider" /> < property name = "net.sf.ehcache.configurationResourceName" value = "/ehcache.xml" /> < property name = "hibernate.cache.use_query_cache" value = "true" /> < property name = "hibernate.cache.use_second_level_cache" value = "true" /> < property name = "hibernate.generate_statistics" value = "true" /> </ properties > |
Добавить аннотацию кеша
Здесь вместо стандартной аннотации гибернации (Cacheable на самом деле, кажется, не работает)
Разместите аннотацию Cache на уровне класса вашего доменного объекта.
1
|
@org .hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE) |
пример
Lazuly приложение
Lazuly — это пример базы данных, содержащей информацию о конференции, которая используется для демонстрации MinuteProject.
Minuteproject генерирует полный набор артефактов для ускорения выпуска приложения OX.
Дополнительную информацию можно найти в витрине Minuteproject 4 Openxava Lazuly .
В этой части мы сосредоточимся на артефактах, сгенерированных для конкретного кэширования.
Минутный проект для генерации основывается на файле конфигурации, где мы определяем модель данных для обратного инжиниринга. В этой конфигурации есть часть обогащения, где вы можете добавить информацию.
Одна из этих сведений касается типа содержимого, которое содержится в объекте. Есть 4 возможности (справочные данные, основные данные, псевдостатические данные, бизнес-данные в реальном времени)
Если вы обогатите свою сущность с помощью content-type = ”master-data” или “reference-data”, MinuteProject 4 Openxava сгенерирует связанное кэширование.
Это сделано здесь для субъекта Страна.
1
|
< entity name = "COUNTRY" content-type = "reference-data" > |
Вот артефакты, связанные с кешем
ehcache.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
49
50
51
52
53
54
55
56
57
|
< ehcache > <!-- Sets the path to the directory where cache files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: * user.home - User's home directory * user.dir - User's current working directory * java.io.tmpdir - Default temp file path Subdirectories can be specified below the property e.g. java.io.tmpdir/one --> <!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @ehcache-main-config-conference@--> < diskStore path = "java.io.tmpdir" /> <!-- Mandatory Default Cache configuration. These settings will be applied to caches created programmtically using CacheManager.add(String cacheName) --> < defaultCache maxElementsInMemory = "1000" eternal = "false" timeToIdleSeconds = "300" timeToLiveSeconds = "300" overflowToDisk = "false" diskPersistent = "false" diskExpiryThreadIntervalSeconds = "300" memoryStoreEvictionPolicy = "LRU" /> <!-- The unnamed query cache --> < cache name = "org.hibernate.cache.StandardQueryCache" maxElementsInMemory = "1000" eternal = "false" timeToLiveSeconds = "300" overflowToDisk = "false" /> <!--MP-MANAGED-UPDATABLE-ENDING--> <!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @cache-entity-country-conference@--> < cache name = "net.sf.mp.demo.conference.domain.admin.Country" maxElementsInMemory = "5000" eternal = "false" timeToIdleSeconds = "300" timeToLiveSeconds = "600" overflowToDisk = "false" /> <!--MP-MANAGED-UPDATABLE-ENDING--> <!--MP-MANAGED-ADDED-AREA-BEGINNING @custom-cache-definition@--> <!--MP-MANAGED-ADDED-AREA-ENDING @custom-cache-definition@--> </ ehcache > |
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
|
xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version = "1.0" > <!-- Tomcat + Hypersonic --> < persistence-unit name = "default" > < non-jta-data-source >java:comp/env/jdbc/conferenceDS</ non-jta-data-source > < class >org.openxava.session.GalleryImage</ class > < properties > < property name = "hibernate.dialect" value = "org.hibernate.dialect.MySQLDialect" /> < property name = "hibernate.cache.provider_class" value = "net.sf.ehcache.hibernate.SingletonEhCacheProvider" /> < property name = "net.sf.ehcache.configurationResourceName" value = "/ehcache.xml" /> < property name = "hibernate.cache.use_query_cache" value = "true" /> < property name = "hibernate.cache.use_second_level_cache" value = "true" /> < property name = "hibernate.generate_statistics" value = "true" /> <!--MP-MANAGED-ADDED-AREA-BEGINNING @properties@--> <!--MP-MANAGED-ADDED-AREA-ENDING @properties@--> </ properties > <!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence-unit@--> <!--MP-MANAGED-ADDED-AREA-ENDING @persistence-unit@--> </ persistence-unit > <!--MP-MANAGED-ADDED-AREA-BEGINNING @persistence@--> <!--MP-MANAGED-ADDED-AREA-ENDING @persistence@--> </ persistence > |
Классовая аннотация
1
2
3
4
5
6
7
8
9
|
@org .hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE) //MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@ //MP-MANAGED-ADDED-AREA-ENDING @class-annotation@ public class Country { @Hidden @Id @Column (name= "id" ) @GeneratedValue (strategy = GenerationType.AUTO) private Integer id; ... |
Сгенерированный код примечания
Сгенерированный код имеет маркеры внутри комментария расширения файла.
В MP-MANAGED-ADDED-AREA-BEGINNING и MP-MANAGED-ADDED-AREA-ENDING вы можете разместить собственный код
В MP-MANAGED-UPDATABLE-BEGINNING-DISABLE и MP-MANAGED-UPDATABLE-ENDING вы можете изменить код. Чтобы сохранить ваши модификации, измените MP-MANAGED-UPDATABLE-BEGINNING-DISABLE на MP-MANAGED-UPDATABLE-BEGINNING-ENABLE.
Обновляемый код предотвращает потерю настроек в течение нескольких поколений.
Для получения дополнительной информации об обновляемом коде см. Обновляемый код Minuteproject .
поколение
- Поместите следующий файл mp-config-LAZULY-OPENXAVA.xml в / mywork / config
- в командной строке выполните mp-model-generation (.sh / cmd) mp-config-LAZULY-OPENXAVA.xml
- результирующие артефакты в / DEV / output / openxava / conference
Для генерации используйте обновленную версию mp-config-LAZULY-OPENXAVA.xml
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
<! DOCTYPE root> < generator-config > < configuration > < conventions > < target-convention type = "enable-updatable-code-feature" /> </ conventions > < model name = "conference" version = "1.0" package-root = "net.sf.mp.demo" > < data-model > < driver name = "mysql" version = "5.1.16" groupId = "mysql" artifactId = "mysql-connector-java" ></ driver > < dataSource > < driverClassName >org.gjt.mm.mysql.Driver</ driverClassName > < url >jdbc:mysql://127.0.0.1:3306/conference</ url > < username >root</ username > < password >mysql</ password > </ dataSource > <!-- for Oracle and DB2 please set the schema <schema> </schema> --> < primaryKeyPolicy oneGlobal = "true" > < primaryKeyPolicyPattern name = "autoincrementPattern" ></ primaryKeyPolicyPattern > </ primaryKeyPolicy > </ data-model > < business-model > <!-- <generation-condition> <condition type="exclude" startsWith="DUAL"></condition> </generation-condition> --> < business-package default = "conference" > < condition type = "package" startsWith = "STAT" result = "statistics" ></ condition > < condition type = "package" startsWith = "COUNTRY" result = "admin" ></ condition > < condition type = "package" startsWith = "ROLE" result = "admin" ></ condition > </ business-package > < enrichment > < conventions > < column-naming-convention type = "apply-strip-column-name-suffix" pattern-to-strip = "_ID" /> < reference-naming-convention type = "apply-referenced-alias-when-no-ambiguity" is-to-plurialize = "true" /> </ conventions > < entity name = "COUNTRY" content-type = "reference-data" > < semantic-reference > < sql-path path = "NAME" /> </ semantic-reference > </ entity > < entity name = "CONFERENCE_MEMBER" > < semantic-reference > < sql-path path = "FIRST_NAME" /> < sql-path path = "LAST_NAME" /> </ semantic-reference > < field name = "STATUS" > < property tag = "checkconstraint" alias = "conference_member_status" > < property name = "PENDING" value = "PENDING" /> < property name = "ACTIVE" value = "ACTIVE" /> </ property > </ field > < field name = "EMAIL" > < stereotype stereotype = "EMAIL" /> </ field > </ entity > < entity name = "SPEAKER" > < field name = "BIO" > < stereotype stereotype = "HTML_TEXT" /> </ field > < field name = "PHOTO" > < stereotype stereotype = "PHOTO" /> </ field > < field name = "WEB_SITE_URL" > < stereotype stereotype = "WEBURL" /> </ field > </ entity > < entity name = "PRESENTATION" > < field name = "STATUS" > < property tag = "checkconstraint" alias = "presentation_status" > < property name = "PROPOSAL" value = "PROPOSAL" /> < property name = "ACTIVE" value = "ACTIVE" /> </ property > </ field > </ entity > < entity name = "SPONSOR" > < field name = "STATUS" > < property tag = "checkconstraint" alias = "sponsor_status" > < property name = "PENDING" value = "PENDING" /> < property name = "ACTIVE" value = "ACTIVE" /> </ property > </ field > < field name = "PRIVILEGE_TYPE" > < property tag = "checkconstraint" alias = "sponsor_privilege" > < property name = "GOLDEN" value = "Golden" /> < property name = "SILVER" value = "Silver" /> < property name = "BRONZE" value = "Bronze" /> </ property > </ field > </ entity > <!-- views --> < entity name = "stat_mb_per_ctry_conf" alias = "MEMBER_PER_COUNTRY_AND_CONFERENCE" > < virtual-primary-key isRealPrimaryKey = "true" > < property name = "virtualPrimaryKey" value = "ID" /> </ virtual-primary-key > </ entity > < entity name = "stat_mb_by_role" alias = "MEMBER_PER_ROLE_COUNTRY_AND_CONFERENCE" > < virtual-primary-key isRealPrimaryKey = "true" > < property name = "virtualPrimaryKey" value = "id" /> </ virtual-primary-key > < field name = "stat_mb_per_ctry_conf_ID" linkToTargetEntity = "stat_mb_per_ctry_conf" linkToTargetField = "id" ></ field > </ entity > </ enrichment > </ business-model > </ model > < targets > <!-- openxava --> < target refname = "OpenXava" name = "OpenXava" fileName = "mp-template-config-openxava-last-features.xml" outputdir-root = "../../DEV/output/openxava/conference" templatedir-root = "../../template/framework/openxava" > </ target > < target refname = "JPA2-LIB" fileName = "mp-template-config-JPA2-LIB.xml" templatedir-root = "../../template/framework/jpa" > </ target > < target refname = "BSLA-LIB" fileName = "mp-template-config-bsla-LIB-features.xml" templatedir-root = "../../template/framework/bsla" > </ target > < target refname = "CACHE-LIB" fileName = "mp-template-config-CACHE-LIB.xml" templatedir-root = "../../template/framework/cache" > </ target > </ targets > </ configuration > </ generator-config > |
Тест
Чтобы убедиться, что кэширование работает правильно:
- Включите запись в спящий режим. Добавьте следующий фрагмент в качестве дополнительных свойств в файле persistence.xml.
1
2
|
< property name = "hibernate.show_sql" value = "true" /> < property name = "hibernate.format_sql" value = "true" /> |
- перейти к объекту, который ссылается на страну (пример адреса)
- Когда вы просматриваете детали этой сущности, вы заметите, что существует связанная с ней сущность «страна».
- Но во второй раз, когда вы получаете доступ к деталям этого объекта (или другого объекта, ссылающегося на тот же экземпляр страны), страна не загружается дважды из базы данных.
Ссылка: Добавление Ehcache в приложение Openxava от нашего партнера JCG