Is it possible to configure expiration of NHibernate's query cache?
For second level cache I can do it from nhibernate.cfg.xml, but I can't find a way for SQL query cache.
EDIT:
ICriteria query = CreateCriteria()
.Add(Expression.Eq("Email", identifiant))
.SetCacheable(true)
.SetCacheRegion("X");
<syscache>
<cache region="X" expiration="10" priority="1" />
</syscache>
Yes, we can set cache expiration via region. Adjust the query like this:
criteria.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.SetCacheRegion("LongTerm");
And put similar configuration into web.config file
<configSections>
<section name="syscache" type="NHibernate.Caches.SysCache.SysCacheSectionHandler, NHibernate.Caches.SysCache" requirePermission="false" />
</configSections>
<syscache>
<cache region="LongTerm" expiration="180" priority="5" />
<cache region="ShortTerm" expiration="60" priority="3" />
</syscache>
EDIT: I am just adding this link Class-cache not used when getting entity by criteria
To be sure what I mean by SQL Query cache. In the linked answer I am explaining that topic
Just for a clarity. The configuration of the NHibernate "session-factory" must contain:
<property name="cache.use_query_cache">true</property>
This switch will make query cache working. More details: http://nhibernate.info/doc/nh/en/index.html#performance-querycache
Related
I have the following config file in my application:
<configuration>
<appSettings>
<!--Setting for user name-->
<add key="wcf:userName" value="wcfuser" />
<!--Setting for password-->
<add key="wcf:userPassword" value="abcdef" />
<!--Setting for is cloud application-->
<add key="IsCloudApplication" value="true" />
</appSettings>
<configuration>
I want remove this comment on the production server via Wix XmlConfig. I tried to use the following code:
<util:XmlConfig Id="RemoveWcfComments" File="[INSTALLFOLDER]Web.config" Action="delete" ElementPath="configuration/appSettings" VerifyPath="<!--Settings for user name-->" Node="element" On="install"/>
,but this is not working: exceptions no occurs, but the comment remains in the config file. Any ideas?
Thank in advance.
I'm not exactly sure but you can try this:
<util:XmlConfig
Id="RemoveWcfComments"
File="[INSTALLFOLDER]Web.config"
Action="delete"
ElementPath="//configuration/appSettings"
VerifyPath="//configuration/appSettings/comment()"
Node="value"
On="install"/>
As you can see ElementPath and VerifyPath are XPath-s, so they are invalid in your code. I'm not sure that Node="value" is right option, you could try Node="element" too.
Using Xpath the Comment() method will select all the the comments underneath AppSettings, if you have multiple comments but want to delete only one, then make use of the xpath below:
VerifyPath="//configuration/appSettings/comment()[.='Settings for user name and password']"
If there are multiple comments and you want to delete the first comment based on the order then you can make use of the below xpath as well:
VerifyPath="//configuration/appSettings/comment()[1]"
I'm trying to get nHibernate to use second-level cache with a many-to-one relationship, however I can't find any clear explanation on how to set it up correctly. I found this How to get nhibernate to cache tables referenced via many-to-one - is my config correct?, but the example sJHonny provided is for one-to-many and it's not working for me when I adopt it. There are other posts going over this subject, but none of them are specific enough.
The XML config I provide works (I had to edit dramatically, so "hopefully" works), but lookup objects are being cached only when they are retrieved as DataObject is queried. I'd like to know 1) where/how to preload the LookupObject collection? 2) what if I assign this collection to a region and set expiration, then where/how do I reload the cache again? 3) how to change the DataObject's hbm.xml such that nHibernate doesn't generate a join with the LOOKUP table, i.e. such that lookup objects always come from the secondary cache, only getting the DATA.LOOKUP_ID from the db, not the LOOKUP.NAME?
LookupObject.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="BusinessObjects" assembly="BusinessObjects">
<class name="LookupObject" table="LOOKUP" mutable="false" batch-size="20">
<cache usage="read-only" />
<id name="Id" column="ID" />
<property name="Name" column="NAME" />
</class>
</hibernate-mapping>
DataObject.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="BusinessObjects" assembly="BusinessObjects">
<class name="DataObject"
table="DATA" mutable="false">
<composite-id>
<key-property name="Id" column="ID"/>
<key-property name="Date" column="DATE" type="Date"/>
</composite-id>
<many-to-one name="LookupObject" not-null="true" column="LOOKUP_ID" fetch="join">
</class>
</hibernate-mapping>
I believe I answered my own questions. 1) For preloading the entire collection, I just needed to change my code such that the entire list of lookups is always pulled from the DB and cached, then I get the individual object by ID with LINQ. 2) Same as before. 3) I haven't tested this yet, but I need to remove fetch="join" from many-to-one element because otherwise the SQL join will still be generated and data will be still returned. Then set the lookup object without nHibernate by getting it from cache.
I'm using the latest EclipseLink version with MySQL 5.5 (table type InnoDB). I'm inserting about 30900 records (which could be also more) at a time.
The problem is, that the insert performance is pretty poor: it takes about 22 seconds to insert all records (compared with JDBC: 7 seconds). I've read that using batch writing should help - but doesn't!?
#Entity
public class TestRecord {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
public int test;
}
The code to insert the records:
factory = Persistence.createEntityManagerFactory("xx_test");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
for(int i = 0; i < 30900; i++) {
TestRecord record = new TestRecord();
record.test = 21;
em.persist(record);
}
em.getTransaction().commit();
em.close();
And finally my EclipseLink configuration:
<persistence-unit name="xx_test" transaction-type="RESOURCE_LOCAL">
<class>com.test.TestRecord</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/xx_test" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="test" />
<property name="eclipselink.jdbc.batch-writing" value="JDBC" />
<property name="eclipselink.jdbc.cache-statements" value="true"/>
<property name="eclipselink.ddl-generation.output-mode" value="both" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.logging.level" value="INFO" />
</properties>
</persistence-unit>
What I'm doing wrong? I've tried several setting, but nothing seems the help.
Thanks in advance for helping me! :)
-Stefan
Another thing is to add ?rewriteBatchedStatements=true to the data URL used by the connector.
This caused executing about 120300 inserts down to about 30s which was about 60s before.
JDBC Batch writing improves performance drastically; please try it
Eg: property name="eclipselink.jdbc.batch-writing" value="JDBC"
#GeneratedValue(strategy = GenerationType.IDENTITY)
Switch to TABLE sequencing, IDENTITY is never recommended and a major performance issue.
See,
http://java-persistence-performance.blogspot.com/2011/06/how-to-improve-jpa-performance-by-1825.html
I seem to remember that MySQL may not support batch writing without some database config as well, there was another post on this, I forget the url but you could probably search for it.
Probably the biggest difference besides the mapping conversion is the caching. By default EclipseLink is placing each of the entities into the persistence context (EntityManager) and then during the finalization of the commit it needs to add them all to the cache.
One thing to try for now is:
measure how long an em.flush() call takes after the loop but before the commit. Then if you want you could call em.clear() after the flush so that the newly inserted entities are not merged into the cache.
Doug
As per the StackOverflow question 'NHibernate and sql timestamp columns as version', I use the following mapping:
<version name="RowNumber" generated="always" unsaved-value="null" type="BinaryBlob">
<column name="RowNumber" not-null="false" sql-type="timestamp" />
</version>
<property name="CreateDate" column="CreateDate" type="DateTime" update="false" insert="false" />
(Other properties after this last).
But when I run my ASP.MVC app I get:
[Path]\Clients.hbm.xml(7,90): XML validation error: The element 'urn:nhibernate-mapping-2.2:version' cannot contain child element 'urn:nhibernate-mapping-2.2:column' because the parent element's content model is empty.
But as far as I can see 2.2 is the latest version of the mapping, so how can anyone put a column element inside the version element?
Sorry if this is really basic,
In case anyone else has this problem:
It works as Ayende Rahien specifies in this blog on NHibernate - but only (AFAIK) on version 2.1.n; I was using 2.0.n. I also think you need the object's field/property to be byte[], not System.Linq.Binary as that type has no default constructor (but I am not sure about this - I seemed to have to do this)
Example (excuse the names):
<version name="RowKludge" type="BinaryBlob" generated="always" unsaved-value="null" >
<column name="RowNumber"
not-null="false"
sql-type="timestamp"/>
</version>
A SQL server 'timestamp' is not your regular timestamp, hence the requirement that the type should be a binary blob.
Note that if you do migrate you will need to change the NHibernate configuration in Web/App config - most tutorials currently available seem to be for v.2.0 (or earlier) - you need an uptodate reference or tutorial for 2.1
A quick look in the documentation reveals that your mapping is not correct. It should be something like this:
<version name="RowNumber" column="RowNumber"
generated="always" unsaved-value="null"
type="Timestamp" />
Best Regards,
Oliver Hanappi
Our application (sadly) uses an MDB back-end database (I.e. JET engine).
One of the items being persisted to the database is an "event" object. The object is persisted to a table with an ID (EventLogID) that is an Autonumber field. The NHibernate mapping is as follows:
<class name="EventLogEntry" table="tblEventLog" proxy="IEventLogEntry">
<id name="Id">
<column name="EventLogID" not-null="true" />
<generator class="native" />
</id>
<property name="Source" column="ErrorLogSource" />
<property name="Text" column="EventLogText" />
<property name="Time" column="EventLogTime" />
<property name="User" column="UserID" />
<property name="Device" column="EventDeviceID" />
</class>
According to the log file, on some occasions when NHibernate attempts to obtain the identity, it receives the value "0". Later, when Flush is called, NHibernate suffers from an assertion failure.
Can anyone suggest why this might be happening? Better yet, can anyone suggest how to fix it?
Regards,
Richard
It could be that the default 'connection-release-mode' configuration setting is the cause of the problems.
A while ago, I ran into a similar issue, and I found that changing the connection.release-mode to 'on_close' (instead of the default after_transaction) solved the issue.
More information can be found on my blog
edit: as I'm thinking of it, perhaps it can be solved without changing the release-mode as well; what happens if you use a transaction to save your event ?
The default release-mode is after transaction, so I'm thinking; perhaps when you use an explicit transaction, the connection will only be closed after the transaction. The question offcourse is, will NHibernate try to retrieve the primary key that has been given to the object inside this transaction, or will it use another transaction ...
If it does not work, then changing the release-mode will solve your problem as well, but it is maybe not the best option.
I think the best option/solution, is to use an explicit transaction first, and see if this solves the problem...