<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5469158129028307538</id><updated>2012-01-14T19:27:48.369-05:00</updated><category term='Hibernate'/><category term='Database'/><title type='text'>Java Robski</title><subtitle type='html'>World of an Architect &lt;br&gt;
~~Lead architect at &lt;a href="http://www.translucentcomputing.com"&gt;www.translucentcomputing.com&lt;/a&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javarobski.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javarobski.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Robert</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5469158129028307538.post-1556466665640974828</id><published>2012-01-10T10:40:00.001-05:00</published><updated>2012-01-10T11:50:51.978-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Extract primary key from hibernate entity</title><content type='html'>&lt;br&gt;&lt;br /&gt;Here is a quick one, I will show you how to extract the primary key and the value from a hibernate entity.&lt;br /&gt;&lt;br /&gt;It took me a while to look at the API and see what I need to use, but after swimming in the API it was a couple of lines that got it all done.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First thing that you need to do is load the entity&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;Parent parent= parentDao.getEntityById(1L);&lt;br /&gt;&lt;/pre &gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Once you load the entity call the following methods (code for the methods will follow)&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;System.out.println("print primary key: " +  HibUtil.extractPrimaryColumn(parent.getClass()) );&lt;br /&gt;System.out.println("print primary key value: " +  HibUtil.extractPrimaryKeyValue(parent,Parent.class) );&lt;br /&gt;&lt;/pre &gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Extract primary column name&lt;/span&gt;&lt;br /&gt;Here is the code for the first method -&gt; extractPrimaryColumn&lt;br /&gt;&lt;br /&gt;Nothing hard about this. First, we load the PersistentClass based on our entity. If all the hibernate mappings are set up correctly there shouldn't be any problems.&lt;br /&gt;&lt;br /&gt;Once we have the PC we then call this method to get the name of the primary key -&gt; getIdentifierProperty().getName();&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;    public static String extractPrimaryColumn(Object entity)&lt;br /&gt;    {&lt;br /&gt;        PersistentClass localPC = extractPersistentClass(entity);&lt;br /&gt;&lt;br /&gt;        //Get pk column and value&lt;br /&gt;        String name = null;&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            name = localPC.getIdentifierProperty().getName();&lt;br /&gt;        }&lt;br /&gt;        catch (PropertyNotFoundException pnfe)&lt;br /&gt;        {&lt;br /&gt;            logger.info("Hib util, property not found",pnfe);&lt;br /&gt;        }&lt;br /&gt;        catch (MappingException me)&lt;br /&gt;        {&lt;br /&gt;            logger.info("mapping not found",me);&lt;br /&gt;        }&lt;br /&gt;        catch (HibernateException he)&lt;br /&gt;        {&lt;br /&gt;            logger.info("hibernate exception........but why??",he);&lt;br /&gt;        }&lt;br /&gt;        catch (NullPointerException npe)&lt;br /&gt;        {&lt;br /&gt;            logger.info("we have a problem getting a value for this entity",npe);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre &gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Extract the value&lt;/span&gt;&lt;br /&gt;Second method uses almost the same logic -&gt; extractPrimaryKeyValue&lt;br /&gt;&lt;br /&gt;After we get the PC we call the following methiod to get the value of the key -&gt; pkValue = (Long) localPC.getIdentifierProperty().getGetter(clazz).get(entity);&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public static Long extractPrimaryKeyValue(Object entity, Class clazz)&lt;br /&gt;    {&lt;br /&gt;        PersistentClass localPC = extractPersistentClass(entity);&lt;br /&gt;&lt;br /&gt;        //Get pk column and value&lt;br /&gt;        Long pkValue = null;&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            pkValue = (Long) localPC.getIdentifierProperty().getGetter(clazz).get(entity);&lt;br /&gt;        }&lt;br /&gt;        catch (PropertyNotFoundException pnfe)&lt;br /&gt;        {&lt;br /&gt;            logger.info("Hib util, property not found",pnfe);&lt;br /&gt;        }&lt;br /&gt;        catch (MappingException me)&lt;br /&gt;        {&lt;br /&gt;            logger.info("mapping not found",me);&lt;br /&gt;        }&lt;br /&gt;        catch (HibernateException he)&lt;br /&gt;        {&lt;br /&gt;            logger.info("hibernate exception........but why??",he);&lt;br /&gt;        }&lt;br /&gt;        catch (NullPointerException npe)&lt;br /&gt;        {&lt;br /&gt;            logger.info("we have a problem getting a value for this entity",npe);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return pkValue;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre &gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In my next post I will expend and show you how I use this code.&lt;br /&gt;&lt;br /&gt;Cheers&lt;br /&gt;&lt;br /&gt;Robert&lt;br /&gt;Lead Architect at &lt;a href="http://www.translucentcomputing.com/"&gt;Translucent Computing&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5469158129028307538-1556466665640974828?l=javarobski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/1556466665640974828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/1556466665640974828'/><link rel='alternate' type='text/html' href='http://javarobski.blogspot.com/2012/01/extract-primary-key-from-hibernate.html' title='Extract primary key from hibernate entity'/><author><name>Robert</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5469158129028307538.post-2578039697985460915</id><published>2010-01-10T23:35:00.000-05:00</published><updated>2011-12-30T12:23:44.444-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Restrictions.sqlRestriction - extract column name from property</title><content type='html'>&lt;div&gt;I been looking around to see if the hibernate API covers this...and I found nothing!!&lt;/div&gt;&lt;div&gt;So  I had to create my own solution!!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The application I am working on has a complex search where the user is able to search different entities and their properties.  This can include dates, strings, and numbers.  The search is like a Google search...using object and their properties. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Problem&lt;/b&gt;&lt;/div&gt;&lt;div&gt;In the API that I created I had to use Restrictions.sqlRestriction as I couldn't do certain things with the Criteria API.  The problem that I found is that when dealing with criteria we are using properties  to apply different restrictions...but in the sqlRestriction we have to use DB column name.   So now I had a problem...how do I apply object properties to sqlRestriction.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Solution &lt;/b&gt;&lt;/div&gt;&lt;div&gt;I created my own Restriction class that uses the SQL and property Name.&lt;br /&gt;I re used some of the code from different part of hibernate API.&lt;br /&gt;So now you can use property name as so {properyName} in your sql (Very simlar how you use the {alias}...not you don't have to use the alias as the property name will get it for you.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre class="brush: java"&gt;public class CustomRestriction&lt;br /&gt;{&lt;br /&gt;public static Criterion sqlRestriction(String sql, String propertyName)&lt;br /&gt;{&lt;br /&gt;    return new CustomSQLCriterion(sql, propertyName, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;public class CustomSQLCriterion implements Criterion&lt;br /&gt;{&lt;br /&gt;private final String sql;&lt;br /&gt;String propertyName;&lt;br /&gt;private final TypedValue[] typedValues;&lt;br /&gt;&lt;br /&gt;public String toSqlString(&lt;br /&gt;        Criteria criteria,&lt;br /&gt;        CriteriaQuery criteriaQuery)&lt;br /&gt;        throws HibernateException&lt;br /&gt;{&lt;br /&gt;    //extract alis and colum name&lt;br /&gt;    String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName);&lt;br /&gt;    StringBuffer fragment = new StringBuffer();&lt;br /&gt;&lt;br /&gt;    //if we have multiple columns....which i will not&lt;br /&gt;    if (columns.length &amp;gt; 1)&lt;br /&gt;    {&lt;br /&gt;        fragment.append('(');&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    //get session factory&lt;br /&gt;    SessionFactoryImplementor factory = criteriaQuery.getFactory();&lt;br /&gt;&lt;br /&gt;    //get column name&lt;br /&gt;    for (int i = 0; i &amp;lt; columns.length; i++)         {             fragment.append(columns[i]);         }          if (columns.length &amp;gt; 1)&lt;br /&gt;    {&lt;br /&gt;        fragment.append(')');&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // repleace propery with column name&lt;br /&gt;    return StringHelper.replace(sql, "{propertyName}", fragment.toString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)&lt;br /&gt;        throws HibernateException&lt;br /&gt;{&lt;br /&gt;    return typedValues;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String toString()&lt;br /&gt;{&lt;br /&gt;    return sql;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected CustomSQLCriterion(String sql, String propertyName, Object[] values, Type[] types)&lt;br /&gt;{&lt;br /&gt;    this.sql = sql;&lt;br /&gt;    this.propertyName = propertyName;&lt;br /&gt;&lt;br /&gt;    typedValues = new TypedValue[values.length];&lt;br /&gt;    for (int i = 0; i &amp;lt; typedValues.length; i++)&lt;br /&gt;    {&lt;br /&gt;        typedValues[i] = new TypedValue(types[i], values[i], EntityMode.POJO);&lt;br /&gt;      }&lt;br /&gt;     }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;table structure&lt;/b&gt;&lt;/div&gt;&lt;div&gt;lets say this is your table structure&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;div&gt;Table Test&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;first_name&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;last_name&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Class Test&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;String fristName;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Sting lastName;&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Usage- &lt;/b&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;CustomRestriction.sqlRestriction("{propertyName} = " + "'test'", "firstName");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Output - &lt;/b&gt;which will be used to construct your query&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;first_name = 'test'&lt;/pre&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5469158129028307538-2578039697985460915?l=javarobski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/2578039697985460915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/2578039697985460915'/><link rel='alternate' type='text/html' href='http://javarobski.blogspot.com/2010/01/restrictionssqlrestriction-extract.html' title='Restrictions.sqlRestriction - extract column name from property'/><author><name>Robert</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5469158129028307538.post-7414936989521085659</id><published>2009-10-17T12:43:00.000-04:00</published><updated>2009-10-17T12:55:36.985-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><title type='text'>SQL server -&gt; Execution plan, parameter sniffing and query hints</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Background info………&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Recently one of our stored procedures had performance problems. The issue was complicated because performance was inconsistent on the same dataset using the same procedure parameters.&lt;span style="mso-spacerun:yes"&gt;    &lt;/span&gt;After some digging it came apparent that this was due to how the SQL server prepares the execution plan for each query inside the stored proc.&lt;span style="mso-spacerun:yes"&gt;   &lt;/span&gt;I could run the same procedure on the same dataset and get a &lt;b&gt;&lt;i&gt;difference of 40 seconds&lt;/i&gt;&lt;/b&gt; on execution.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Investigation……&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;When I hooked up the SQL server profiler I was able to extract the execution plan for the query in the store procedure that was causing the problem.&lt;span style="mso-spacerun:yes"&gt;    &lt;/span&gt;I was able to find that depending of the execution sequence this query would have &lt;b&gt;&lt;i&gt;2 different exestuation plans.&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;b&gt;&lt;i&gt;Sequence 1:&lt;/i&gt;&lt;/b&gt;&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;I recompile the stored proc and run it on small dataset first then on a bigger dataset, the proc would be really slow on the bigger dataset.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;b&gt;&lt;i&gt;Sequence 2:&lt;/i&gt;&lt;/b&gt;&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;I recompile the stored proc and run it on the bigger dataset first (same data, same parameters) the sorted proc runs fast (40 seconds difference)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Something to keep in mind that the stored proc only ran slow in a jasper report, if I re run the proc in the SQL server it would be fast.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;So when testing, be sure to test it inside a report.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Execution plan……&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;As you know the DB will try to create an execution plan for query(non trivial) that is executed, unless there is one that already exists in the cache, in that case it will re use an execution plan.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;SQL server uses cost-based technique to determine the processing strategy.&lt;span style="mso-spacerun:yes"&gt;   &lt;/span&gt;The query will use metadata of the database objects and current statistics to decide with indexes and what join strategies to use.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The overall time required to execute a query is the sum of the time required to generate the execution plan and the execution of the query.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The cost incurred in the generation of the execution plan depends on the process of generating the execution plan, the process of caching the plan and the reusability of the plan.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;When it comes to execution plans for procedures they are no generated when you create the procedure, it gets created and cached first time you run it.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;…..there is much much more, but this should be enough to see the problem in our case&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Parameter sniffing…..&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;em&gt;&lt;span style="Arial&amp;quot;,&amp;quot;sans-serif&amp;quot;font-family:&amp;quot;;"&gt;"Parameter sniffing" refers to a process whereby SQL Server's execution environment "sniffs" the current parameter values during compilation or recompilation, and passes it along to the query optimizer so that they can be used to generate potentially faster query execution plans. The word "current" refers to the parameter values present in the statement call that caused a compilation or a recompilation.&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;The problem with parameter sniffing is that if you have procedures that return wide range of data the execution of the procedure will change………dramatically in our case.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If you run a procedure for the first time with small dataset, there will be execution plans created for queries in the procedure…. not necessarily efficient ones.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;So that if you re-run the same proc with bigger dataset the performance will suffer do to re-use of inefficient execution plan.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;In some cases this can be fixed by creating local variable in the procedure and assigning the parameter variables to the local ones.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This will confuse the query analysis and it will create an execution plan based on statistics.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This might or might not be good.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Depending on your situation, but it’s worth trying.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;a) Sniffing enabled--- execution plan based on the parameter passed&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.25in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;CREATE PROCEDURE GetUser&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;@UserName nvarchar(20)&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;AS&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;BEGIN&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;select * from user where username = @UserName&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;END&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;&lt;b&gt;&lt;i&gt;b) Sniffing disabled --- execution plan based on statistic due to local variable&lt;/i&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;CREATE PROCEDURE GetUser&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;@UserName nvarchar(20)&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;AS&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;BEGIN&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;DECLARE @myUserName nvarchar(20)&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;SET @myUserName = @UserName&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;select * from user where username = @myUserName&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;END&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;&lt;span style="mso-spacerun:yes"&gt; &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b style="mso-bidi-font-weight:normal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Query hints………..option (recompile)&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If the disabling of the parameter sniffing didn’t fix the problem, and the execution plan created is still slow, another option is to play around with the query hints.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;span style="mso-spacerun:yes"&gt; &lt;/span&gt;What I end up using is a hint that recompiles the specified query when it’s executed every time:&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;b&gt;&lt;i&gt;option (recompile)&lt;/i&gt;&lt;/b&gt;.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;This option is not placed on the whole procedure but only on specific query inside the procedure. &lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;CREATE PROCEDURE GetUser&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;@UserName nvarchar(20)&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;AS&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;BEGIN&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;&lt;span style="mso-tab-count:1"&gt;                &lt;/span&gt;select * from user where username = @UserName &lt;b&gt;&lt;i&gt;option (recompile)&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-top:0in;margin-right:0in;margin-bottom:0in; margin-left:.5in;margin-bottom:.0001pt;line-height:normal"&gt;END&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"&gt;You have to be careful when using this option as in some case the creation of the execution plan could be costly and provide bigger over head.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Conclusion……….&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;In the end I was able to use query hint recompile to fix my problem and get a good constant execution of the procedure. I don’t have to care about different data ranges as every time the procedure executes it creates a low cost execution plan for the troubled query.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5469158129028307538-7414936989521085659?l=javarobski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/7414936989521085659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/7414936989521085659'/><link rel='alternate' type='text/html' href='http://javarobski.blogspot.com/2009/10/my-pain-wiht-sql-serverexecution-plan.html' title='SQL server -&gt; Execution plan, parameter sniffing and query hints'/><author><name>Robert</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-5469158129028307538.post-8654282748505340779</id><published>2008-03-27T12:54:00.001-04:00</published><updated>2008-03-28T14:33:47.527-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate - DB audit Logging</title><content type='html'>Hibernate -DB audit logging (How about this....................)&lt;br /&gt;&lt;span style="font-size:78%;"&gt;(Leave me a note if  you have any comments improvements, corrections)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I looked around the web to see if there is any logging that can be done on the entities  that are persisted using hibernate.&lt;br /&gt;&lt;br /&gt;I found one interesting post on the hibernate site, one thing was missing:&lt;br /&gt;The logging done in this article is based on entities names (the process will parse out the method name and the class name, and it will use that as the names of the columns and tables).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.hibernate.org/318.html"&gt;http://www.hibernate.org/318.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I needed the logging to be more precise.&lt;br /&gt;I needed the logger to match exact table name and the exact column name that the value was saved to. Yes you can do if you have your java entities names mapped to the DB tables and column names, as in the article above.&lt;br /&gt;&lt;br /&gt;in the above example if you have Table called TEST_TABLE, the extracted value that will be saved using the audit logger will be TestTable(most likely that will be the name of the class that mapps to the table).&lt;br /&gt;The same will be for the column: FIRST_NAME  will be mapped to firstName.&lt;br /&gt;I want to log the column name as it's represented in the DB&lt;br /&gt;So if I have a Column called FIRST_NAME, i want to logged in the DB as FIRST_NAME = Robert.&lt;br /&gt;&lt;br /&gt;SO ...Logging it the right way.........&lt;br /&gt;here is what i did&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;1) DB structure&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Action log&lt;/span&gt; DB structure, this where i will save all my changes.&lt;br /&gt;&lt;blockquote&gt;Table: ACTION_LOG&lt;br /&gt;Column: ACTION_LOG_ID - &gt; primary key&lt;br /&gt;Column: USER_ID -&gt; number&lt;br /&gt;Column: TABLE_NAME - &gt; varchar&lt;br /&gt;Column: PRIMARY_KEY - &gt; varchar&lt;br /&gt;Column: CONCAT_VALUES- &gt; varchar (values that are saved)&lt;br /&gt;Column: COMMAND -&gt; varchar&lt;br /&gt;Column: TIME_STAMP&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Test Entity&lt;/span&gt; - This will be my test entity i will try to persist and audit&lt;br /&gt;&lt;blockquote&gt;Table: TEST_TABLE&lt;br /&gt;Column 1: TEST_TABLE_ID -&gt; primary key&lt;br /&gt;Column 2: FIRST_NAME-&gt; varchar2&lt;br /&gt;Column 3: POSITION - &gt; varchar2&lt;/blockquote&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;2) Hibernate Mappings (using annotations)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hibernate mapping of ACTION_LOG&lt;br /&gt;&lt;blockquote&gt;@Entity&lt;br /&gt;public class ActionLog implements Serializable {&lt;br /&gt;private static final long serialVersionUID = -9176091358716821364L;&lt;br /&gt;private Long logId;&lt;br /&gt;private Long userId;&lt;br /&gt;private Timestamp timeStamp;/&lt;br /&gt;private String tableName;&lt;br /&gt;private String pkColumn;&lt;br /&gt;private String command;&lt;br /&gt;private String concatValues;&lt;/blockquote&gt;Hibernate mapping for TEST_TABLE&lt;br /&gt;&lt;blockquote&gt;@Entity&lt;br /&gt;public class  TestTable&lt;br /&gt;private String firstName;&lt;br /&gt;private String position;&lt;br /&gt;private Long testTableId;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;3) Create logger DAO and Service&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;I use layered architecture in my application, so I  create a DAO and a service for the ActionLog class which i will use in my logger when i persist my data.&lt;br /&gt;&lt;br /&gt;You will notice that my actionLog DAO is empty. All my basic methods for saving/updating/deleting are located in my base class that the DAO is extanding.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;public interface ActionLogService {&lt;br /&gt;&lt;br /&gt;void createActionLog(ActionLog actionLog);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class AuditLogServiceImpl  implements ActionLogService{&lt;br /&gt;&lt;br /&gt;@Autowired&lt;br /&gt;private AuditLogDao auditLogDao;&lt;br /&gt;&lt;br /&gt;public AuditLogServiceImpl () {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void createActionLog (ActionLog actionLog) {&lt;br /&gt;auditLogDao.add (actionLog);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public interface ActionLogDao {}&lt;br /&gt;&lt;br /&gt;@Repository("auditLogDAO")&lt;br /&gt;public class AuditLogDAOImpl extends BaseDAOHibImpl&lt;actionlog&gt; implements AuditLogDao {}&lt;br /&gt;&lt;br /&gt;&lt;/actionlog&gt;&lt;/blockquote&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;4) Create HibernateInterceptor&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We will use the hibernate interceptor to log the changes.&lt;br /&gt;As you can see we log on :&lt;br /&gt;onFlushDirty&lt;br /&gt;onSave&lt;br /&gt;onDelete&lt;br /&gt;&lt;br /&gt;Every time you try to perform a hibernate update, save or delete one of the methods will run and checks if an audit needs to be done&lt;br /&gt;&lt;br /&gt;Couple things to notice that i have here&lt;br /&gt;1)user_id, currently it's set to -1.  I save this value in my db logger.&lt;br /&gt;In my code implementation I inject a session bean that holds the user id&lt;br /&gt;2)I use annotations to register my bean&lt;br /&gt;&lt;blockquote&gt;@Service("hibernateInterceptor")&lt;br /&gt;public class HibernateInterceptor extends EmptyInterceptor implements ApplicationContextAware{&lt;br /&gt;&lt;br /&gt;private static final long serialVersionUID = -3073850856829239762L;&lt;br /&gt;&lt;br /&gt;@Autowired&lt;br /&gt;@Qualifier("commonsActionLogger")&lt;br /&gt;private ActionLogger theLogger;&lt;br /&gt;&lt;br /&gt;private ApplicationContext context;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Creates a new instance of HibernateLoggingInterceptor&lt;br /&gt;*/&lt;br /&gt;public HibernateInterceptor () {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public boolean onLoad (Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {&lt;br /&gt;return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public boolean onFlushDirty(Object entity, Serializable id, Object[] newValues, Object[] oldValues, String[] propertyNames, Type[] types) throws CallbackException {&lt;br /&gt;if (!(entity instanceof LogStopper)){&lt;br /&gt;theLogger.logThis ("Update",entity,propertyNames,getUserId());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private Long getUserId() {&lt;br /&gt;return -1L;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public boolean onSave (Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {&lt;br /&gt;if (!(entity instanceof LogStopper)){&lt;br /&gt;theLogger.logThis ("Create",entity,propertyNames,-getUserId());&lt;br /&gt;}&lt;br /&gt;return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public void onDelete (Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {&lt;br /&gt;if (!(entity instanceof LogStopper)){&lt;br /&gt;theLogger.logThis ("Delete",entity,propertyNames,getUserId());&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setApplicationContext(ApplicationContext arg0)&lt;br /&gt;throws BeansException {&lt;br /&gt;this.context=arg0;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;5)Register the intercept&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Register the following property in your sessionFactory&lt;br /&gt;&lt;blockquote&gt;property name="entityInterceptor" ref="hibernateInterceptor"&lt;/blockquote&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;6) Create THE LOGGER&lt;br /&gt;&lt;/span&gt;Here is the fun stuff, here is where we hack in to the session factory and extract data so we can parse out the DB info so we can save the data&lt;br /&gt;&lt;br /&gt;I have 2 classes and 1 interface here&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;AtionLoggecr  &lt;/span&gt;interface&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;DatabaseActionLoger &lt;/span&gt;-&gt; this is where i save the audited entity to the DB&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ParseHibEntity &lt;/span&gt;- This is a util class where i hack in to the session factory and get all the info i need to save the audited entity ( I get the table info and the value that is persisted)&lt;br /&gt;&lt;blockquote&gt;public interface ActionLogger {&lt;br /&gt;&lt;br /&gt;void logThis (String command, Object entity, String[] properties,Long userId) ;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class DatabaseActionLogger implements ActionLogger{&lt;br /&gt;&lt;br /&gt;@Autowired&lt;br /&gt;private ActionLogService actionLogService;&lt;br /&gt;&lt;br /&gt;public void logThis(String command, Object entity, String[] properties,Long userId) {&lt;br /&gt;&lt;br /&gt;if (!(entity instanceof ActionLog)){&lt;br /&gt;&lt;br /&gt;  //new actionlog&lt;br /&gt;  ActionLog actionLog = new ActionLog();&lt;br /&gt;&lt;br /&gt;  //prse object, get all the methods&lt;br /&gt;  ParseHibEntity phe = new ParseHibEntity(entity,properties);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  //set command and table name&lt;br /&gt;  actionLog.setCommand(command);&lt;br /&gt;  actionLog.setTableName(phe.extractTableName());&lt;br /&gt;&lt;br /&gt;  //primary key column&lt;br /&gt;  actionLog.setPkColumn(phe.extractPrimaryKeyColumn());&lt;br /&gt;&lt;br /&gt;  //save all contact values&lt;br /&gt;  actionLog.setConcatValues(phe.extractColumnValues());&lt;br /&gt;&lt;br /&gt;  //set time stemp&lt;br /&gt;  actionLog.setTimeStamp(new Timestamp(new Date().getTime()));&lt;br /&gt;  actionLog.setUserId(userId);&lt;br /&gt;&lt;br /&gt;  //save the actionlog&lt;br /&gt;  actionLogService.createActionLog(actionLog);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ParseHibEntity {&lt;br /&gt;private Logger log = Logger.getLogger(this.getClass());&lt;br /&gt;private PersistentClass pc = null;&lt;br /&gt;private Object entity;&lt;br /&gt;private String[] properties;&lt;br /&gt;&lt;br /&gt;public static final String DATE_FORMAT = "yyyy-MM-dd";&lt;br /&gt;public static final String DATE_TIME_FORMAT = "yyyy-MM-dd hh:mm:ss a";&lt;br /&gt;/**&lt;br /&gt;* Creates a new instance of ParseHibEntity&lt;br /&gt;*/&lt;br /&gt;public ParseHibEntity(Object entity, String[] properties) {&lt;br /&gt;this.pc = extractPersistentClass(entity.getClass().getName());&lt;br /&gt;this.entity = entity;&lt;br /&gt;this.properties = properties;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private PersistentClass extractPersistentClass(String entityName){&lt;br /&gt;PersistentClass pc = null;&lt;br /&gt;LocalSessionFactoryBean sessionFactory = null;&lt;br /&gt;try {&lt;br /&gt;  sessionFactory = (LocalSessionFactoryBean)AppCtxHolder.getApplicationContext().getBean("&amp;amp;mySessionFactory");&lt;br /&gt;  pc = ((LocalSessionFactoryBean)sessionFactory).getConfiguration().getClassMapping(entityName);&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.error("NullPointerException - make sure you get the right session factory " + npe.getMessage(),npe);&lt;br /&gt;}&lt;br /&gt;return pc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String extractPrimaryKeyValue(){&lt;br /&gt;//Get pk column and value&lt;br /&gt;String pkValue = null;&lt;br /&gt;try{&lt;br /&gt;  pkValue = pc.getIdentifierProperty().getGetter(entity.getClass()).get(entity).toString();&lt;br /&gt;}catch(PropertyNotFoundException pnfe){&lt;br /&gt;  log.info("PropertyNotFoundException " + pnfe.getMessage());&lt;br /&gt;}catch(MappingException me){&lt;br /&gt;  log.info("MappingException " + me.getMessage());&lt;br /&gt;}catch(HibernateException he){&lt;br /&gt;  log.info("HibernateException " + he.getMessage());&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.info("NullPointerException " + npe.getMessage());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return pkValue;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String  extractPrimaryKeyColumn(){&lt;br /&gt;String pkColumn = null;&lt;br /&gt;try{&lt;br /&gt;  pkColumn = ((Column)pc.getIdentifierProperty().getColumnIterator().next()).getName();&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.info("NullPointerException " + npe.getMessage());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return pkColumn;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String  extractPrimaryKeyColumn(PersistentClass localPC){&lt;br /&gt;String pkColumn = null;&lt;br /&gt;try{&lt;br /&gt;  pkColumn = ((Column)localPC.getIdentifierProperty().getColumnIterator().next()).getName();&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.info("NullPointerException " + npe.getMessage());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return pkColumn;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String extractPrimaryKeyValue(PersistentClass localPC, Object localEntity){&lt;br /&gt;//Get pk column and value&lt;br /&gt;String pkValue = null;&lt;br /&gt;try{&lt;br /&gt;  pkValue = localPC.getIdentifierProperty().getGetter(localEntity.getClass()).get(localEntity).toString();&lt;br /&gt;}catch(PropertyNotFoundException pnfe){&lt;br /&gt;  log.error("PropertyNotFoundException " + pnfe.getMessage(),pnfe);&lt;br /&gt;}catch(MappingException me){&lt;br /&gt;  log.error("MappingException " + me.getMessage(),me);&lt;br /&gt;}catch(HibernateException he){&lt;br /&gt;  log.error("HibernateException " + he.getMessage(),he);&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.error("NullPointerException " + npe.getMessage(),npe);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return pkValue;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("unchecked")&lt;br /&gt;public String extractColumnValues(){&lt;br /&gt;StringBuffer sb = new StringBuffer();&lt;br /&gt;&lt;br /&gt;//add the pk column and value&lt;br /&gt;sb.append(extractPrimaryKeyColumn() + " = " + extractPrimaryKeyValue() + " | ");&lt;br /&gt;//System.out.println("pc.getProperty (scale) " + pc.getProperty ("scale"));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//loop through all the other properties and get what you need&lt;br /&gt;for (String p: properties){&lt;br /&gt;  Property pr = pc.getProperty(p);&lt;br /&gt;&lt;br /&gt;  //make sure that this is not a collection and not a one to one as these values are not part of the table&lt;br /&gt;  if (!pr.getType().isCollectionType() &amp;amp;&amp;amp; !(pr.getType() instanceof OneToOneType)){&lt;br /&gt;&lt;br /&gt;      //make sure that the values are persistent values and not a forumla value&lt;br /&gt;      if (pr.isInsertable() || pr.isUpdateable()) {&lt;br /&gt;          int scale = 2;&lt;br /&gt;&lt;br /&gt;          //get the getter for the entity&lt;br /&gt;          Getter getter = pr.getGetter(entity.getClass());&lt;br /&gt;&lt;br /&gt;          //get column value&lt;br /&gt;          Object columnValue = getter.get(entity);&lt;br /&gt;&lt;br /&gt;          //get column name&lt;br /&gt;          for (Iterator it3 = pr.getColumnIterator(); it3.hasNext(); ) {&lt;br /&gt;              Column column = (Column)it3.next();&lt;br /&gt;              sb.append(column.getName());&lt;br /&gt;              scale = column.getScale();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          sb.append(" = ");&lt;br /&gt;&lt;br /&gt;          //check what kind of type of value this is, it if it an association then get the forign key value from the associated entity&lt;br /&gt;          if (columnValue != null){&lt;br /&gt;              if (!pr.getType().isAssociationType()){&lt;br /&gt;       &lt;br /&gt;                  //if bigD set Scale&lt;br /&gt;                  if (columnValue instanceof BigDecimal){&lt;br /&gt;                      columnValue = ((BigDecimal)columnValue).setScale(scale,BigDecimal.ROUND_HALF_DOWN);&lt;br /&gt;                  }else if (columnValue instanceof java.util.Date){&lt;br /&gt;                      SimpleDateFormat sdf = null;&lt;br /&gt;                      if(columnValue instanceof java.sql.Timestamp){&lt;br /&gt;                          sdf = new SimpleDateFormat(DATE_TIME_FORMAT);&lt;br /&gt;                      }else{&lt;br /&gt;                          sdf = new SimpleDateFormat(DATE_FORMAT);&lt;br /&gt;                      }&lt;br /&gt;                      columnValue = sdf.format(columnValue);&lt;br /&gt;                  } else if (pr.getType().getName().equalsIgnoreCase("org.springframework.orm.hibernate3.support.ClobStringType")){&lt;br /&gt;                      columnValue = "Clob Value";&lt;br /&gt;                  }&lt;br /&gt;                                &lt;br /&gt;                  sb.append(columnValue);&lt;br /&gt;              }else{&lt;br /&gt;                  //since it's an association we know that column value is an object&lt;br /&gt;                  String associatedEntityName = pr.getType().getName();&lt;br /&gt;                  //associatedEntityName = ((EntityType)pr.getType()).getAssociatedEntityName ();&lt;br /&gt;                  PersistentClass localPC = extractPersistentClass(associatedEntityName);&lt;br /&gt;                  String fkValue = extractPrimaryKeyValue(localPC,columnValue);&lt;br /&gt;                  sb.append(fkValue);&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;          sb.append(" | ");&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;return sb.toString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String extractTableName(){&lt;br /&gt;try {&lt;br /&gt;  return pc.getTable().getName();&lt;br /&gt;}catch(NullPointerException npe){&lt;br /&gt;  log.error("NullPointerException - table is null " + npe.getMessage(),npe);&lt;br /&gt;  return "";&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;7)Using IT&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;No all you have to do is persit you data, so if you do the following&lt;br /&gt;&lt;br /&gt;TestDAO.save(TestEntity):&lt;br /&gt;the logger will save save the following if no in the ACTION_LOG&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LOG_ID&lt;/span&gt; = 1&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;USER_ID&lt;/span&gt; = -1&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TABLE_NAME&lt;/span&gt; = TEST TABLE&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;PRIMARY_KEY&lt;/span&gt; = 1&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CONCAT_VALUES&lt;/span&gt; = FIRST_NAME = JavaRobski | POSITIONS = Architect&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;COMMAND = SAVE&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TIME_STAMP&lt;/span&gt; = 2008-09-01&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5469158129028307538-8654282748505340779?l=javarobski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/8654282748505340779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5469158129028307538/posts/default/8654282748505340779'/><link rel='alternate' type='text/html' href='http://javarobski.blogspot.com/2008/03/hibernate-audit-logging-right-way.html' title='Hibernate - DB audit Logging'/><author><name>Robert</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
