Recently, Kun Ge recommended me to use JavaMelody, a performance monitoring and tuning tool. It made me feel that project optimization is visible and targeted. Whether distributed or non-distributed, caching is an effective tool for prompting performance.
The data layer is implemented by EJB3.0, while EJB3.0 is implemented by Hibernate internally. Hibernate itself provides a good caching mechanism. We only need to learn how to use it to control it.
The cache function can be simply understood as storing the data accessed from the database in the memory. when the data is used again in the future, it can be directly read from the memory without having to access the database again, minimize interactions with databases to improve performance.
Concepts
Hibernate provides two caching mechanisms: level-1 cache and level-2 Cache. Because level-2 Cache policies are cache policies for ID queries, they do not work for conditional queries. Therefore, hibernate provides Query Cache for conditional queries ).
I. Level 1 cache:
A level-1 cache comes with hibernate and is not subject to user intervention. its lifecycle is the same as that of the session. Once the current session is closed, the level-1 cache disappears. Therefore, A level-1 cache is also called session cache or transaction-level cache,The first-level cache only stores entity objects and does not cache general object attributes,That is, after an object is obtained, the object will be cached. if the object is obtained again in the same session, it will first determine whether the ID of the object is in the cache, if yes, it will be taken directly from the cache. Otherwise, the database will be accessed and the object will be cached at the same time.
Ii. Secondary cache:
The second-level cache is also called a process cache or sessionFactory-level cache. It can be shared by all sessions. The second-level cache has the same lifecycle as sessionFactory,The second-level cache also stores only entity objects..
The general process of second-level cache is as follows:
①: Obtain the queried object during condition query.
②: Put all the data objects obtained into the second-level cache by ID
③: When Hibernate accesses the Data Object Based on the ID, it first queries the sesison level-1 cache. If the level-2 cache is configured when it cannot be found, it will find it in the level-2 cache, if not, query the database and put the result into the cache by ID.
④: The cache will be updated simultaneously during the delete, update, and add operations.
Iii. query cache:
The query cache caches the result set of common attributes and only the id of the result set of the object. If the query cache is enabled for frequently used query statements, when you execute a query statement for the first time, Hibernate stores the query results in the second-level cache. When you execute the query statement again later, you only need to obtain the query results from the cache to improve the query performance,The query cache is stored as a key-value pair,KeyThe key is the query Condition Statement (the specificKeyThe rule should be: Class Name+Method Name+Parameter List ),ValueTheIDList.
The general process of querying cache is as follows:
①: The Query Cache stores the SelectSQL statements executed in the previous Query, and the result set and other information into a Query Key.
②: When a query request is encountered again, it will be searched from the QueryCache Based on the QueryKey, and will be returned if it is found. However, when the data table changes, hbigoal will automatically clear the Query Key corresponding to the QueryCache
We can see from the Query Cache Policy that the Query Cache only works under specific conditions and has strict requirements:
①: Repeated execution of identical SelectSQL statements
②: During Repeated execution, the data table corresponding to the QueryKey cannot be changed.
Enable cache Configuration
Configure query cache and second-level cache in EJB
1. Enable cache in persistence. xml
<Persistence-unitname = "gxpt-qx-entity" transaction-type = "JTA"> <! -- Test the performance of jpa --> <provider> net. bull. javamelody. jpaPersistence </provider> <jta-data-source> java:/MySqlDS </jta-data-source> <! -- <Jta-data-source> java:/MyOracleDS </jta-data-source> --> <properties> <! -- <Propertyname = "hibernate. dialect "value =" org. hibernate. dialect. oracle10gDialect "/> --> <propertyname =" hibernate. dialect "value =" org. hibernate. dialect. mySQLDialect "/> <propertyname =" hibernate. hbm2ddl. auto "value =" update "/> <propertyname =" hibernate. show_ SQL "value =" true "/> <! -- Specify the provider of the second-level cache product --> <propertyname = "hibernate. cache. provider_class" value = "net. sf. ehcache. hibernate. SingletonEhCacheProvider"/> <! -- <Propertyname = "hibernate. cache. region. factory_class" value = "org. hibernate. cache. ehcache. EhCacheRegionFactory"/> --> <! -- Enable Level 2 cache --> <propertyname = "hibernate. cache. use_second_level_cache" value = "true"/> <! -- Enable query cache --> <propertyname = "hibernate. cache. use_query_cache" value = "true"/> <! -- Specify the cache configuration file location --> <propertyname = "hibernate. cache. provider_configuration_file_resource_path" value = "/ehcache. xml"/> </properties> </persistence-unit>
2. Specify the User class using Level 2 Cache through Annotation
@Entity@Table(name="tq_user")@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)publicclass User
3. Enable query cache. In addition to the above configuration in persistence. xml, you also need to manually enable query cache in the underlying code.
Query. setHint ("org. hibernate. cacheable", true );
Or query. setCacheable (true );
Performance test passed SQL statements
1. When the second-level cache is disabled, check whether the cache is enabled or disabled. ***** common attribute Query
public String myCache() { List<String> strings = this.userServiceImpl .search("selectu.username from User u where id<4 order by id asc"); for (String str : strings){ System.out.println("username:" + str); } System.out.println("==================================="); List<String> strings2 =this.userServiceImpl .search("select u.usernamefrom User u where id<4 order by id asc"); for (String str : strings2){ System.out.println("username:" + str); } return "/mycache"; }
The current second-level cache is disabled. Check the query results when the query cache is disabled:
Public List <String> search (Stringhql) {List <String> rtnStrs = newArrayList <String> (); try {Session session = this. sessionFactory. openSession (); session. beginTransaction (); Query query = session. createQuery (hql); // query. setCacheable (true); // manually enable the query cache rtnStrs = (List <String>) query. list (); session. getTransaction (). commit ();} catch (Exception e) {System. out. println ("failed to query by HQL statement in DAO layer");} return rtnStrs ;}
The preceding Code shields query. setCacheable (true ).
Disable the second-level cache, and disable the query cache to run the following code:
Enable the query cache and disable the second-level cache for running as follows:
Conclusion: no matter whether the second-level cache is enabled or not, if the query cache is enabled, when the two executed SQL statements are the same, the second SQL statement will not be issued, directly from the memory.
2. When the query cache is turned on, the second-level cache is turned on and off. *******
/***** Query cache is enabled, and the second-level cache is disabled ******** query object ** running result: If the query cache and second-level cache are disabled, when an SQL statement is issued during two queries, the two query statements ** run the result: If the query cache is enabled, the second-level cache is disabled, the second query will issue n query statements for the object based on the ID **. Conclusion: when the list is executed for the first time, the query object ID will be cached in the query cache, when you execute the list for the second time (the SQL statements for the two queries are the same), the IDs in the query cache will be traversed to the * (level 1 and level 2) cache to find the object. At this time, no, then the query statement is issued to the database for query **/publicString mycache3 () {List <User> users1 = this. userServiceImpl. search (); for (User u: users1) {System. out. println ("users1: username:" + u. getUsername ();} System. out. println ("=================="); List <User> users2 = this. userServiceImpl. search (); for (User u: users2) {System. out. println ("users2: usersname:" + u. getUsername ();} return "/mycache ";}
Enable the query cache and disable the second-level cache to run the following code: (both SQL statements are issued and n statements are issued for the second time)
Enable the query cache and disable the second-level cache for running as follows (only one statement is issued)
Summary:
(1) When you only use hibernate to query the cache and disable the second-level cache:
① If some property result sets are queried, the SQL statement will not be issued during the second query and the data will be retrieved directly from the Hibernate query cache.
② If the object result set is queried (eg. from User) This HQL, then the queried object first, hibernate queries the cache to store the Object ID, the second query, go to the hibernate query cache and retrieve the ID one by one to the database query. In this way, n SQL statements will be issued, resulting in SQL flooding. Therefore, it is best to enable the second-level cache when using the query cache.
(2) When Hibernate query cache and secondary cache are enabled:
① If some property result sets are queried, this is the same as that when only the hbiweekly query cache is used and the second-level cache is disabled. Because no entity is involved, the second-level cache is not used.
② If the object result set is queried, The queried object first stores the Object ID in the query cache and saves the object to the second-level cache. During the second query, obtain the ID in the hibernate query cache and match the data in the second-level cache based on the ID. If there is any data, no SQL statement will be issued, no SQL statement is issued for the second query, and data is directly retrieved from the second-level cache.
Use Javamelody
JavaMelody can monitor Java or Java EE application servers in the runtime environment. The following charts show the usage of Java memory and Java CPU, the number of user sessions, and the number of JDBC connections, and the number of http requests, SQL requests, jsp pages, and business interface methods (EJB3, Spring, and Guice), average execution time, and error percentage.
Kun GE's blog introduces Java project performance monitoring and tuning tools-Javamelody
Monitor project cache count
This is the cache in the permission project for this development. There are 12 in total, and the red part is the second-level cache and query cache respectively.
Monitoring of spring
Cache Addition
No cache Conditions
According to the statistical results, it is found that the cache can indeed improve the performance.
However, sometimes when cache is used, the performance will be reduced. For example, after the data is changed, hibernate needs to keep the data in the cache and the database synchronized. Therefore, after the cache is added, the performance of update is reduced. The add and delete operations are the same.
Therefore, the cache is applicable when a large number of queries exist in the project. Otherwise, it is unnecessary.
Summary
It is important to think that the project is very attractive to you because we are using a variety of tools, including the cache and javamelody mentioned here, "The use of more tools will be detailed later.