Hibernate Cache
Beim Caching geht es um die Optimierung der Anwendungsleistung. Es befindet sich zwischen der Anwendung und der Datenbank, um mehrere Datenbankzugriffe zu vermeiden und eine bessere Leistung leistungskritischer Anwendungen zu ermöglichen.
Caching ist für Hibernate sehr wichtig, das ein mehrstufiges Caching-Schema verwendet, wie unten beschrieben:
Cache der ersten Ebene:
Cache der ersten Ebene Es handelt sich um den Sitzungscache und einen obligatorischen Cache, den alle Anforderungen durchlaufen müssen. Das Sitzungsobjekt behält seine eigene Macht als Objekt, bevor es an die Datenbank übermittelt wird.
Wenn für ein Objekt mehrere Updates ausgegeben werden, versucht Hibernate, die Updates so lange wie möglich zu verzögern, um die Anzahl der ausgegebenen Update-SQL-Anweisungen zu reduzieren. Wenn Sie die Sitzung schließen, gehen alle zwischengespeicherten Objekte verloren, bleiben entweder bestehen oder werden in der Datenbank aktualisiert.
L2-Cache:
Der L2-Cache ist ein optionaler Cache und der L1-Cache wird immer konsultiert, bevor versucht wird, ein Objekt im L2-Cache zu finden. Der Cache der zweiten Ebene kann pro Klasse und pro Sammlung konfiguriert werden und ist für das Zwischenspeichern von Objekten innerhalb der Sitzung verantwortlich.
Jeder Drittanbieter-Cache kann Hibernate verwenden. Die Schnittstelle org.hibernate.cache.CacheProvider stellt eine Handle-Cache-Implementierung bereit, die implementiert werden muss, um Hibernate bereitzustellen.
Cache auf Abfrageebene:
Hibernate implementiert auch die enge Integration von Abfrageergebnis-Cache und sekundärem Cache.
Dies ist eine optionale Funktion, die zwei zusätzliche physische Caches erfordert, um zwischengespeicherte Abfrageergebnisse und den Zeitstempel der letzten Aktualisierung einer Tabelle zu speichern. Dies ist nur für Abfragen sinnvoll, die häufig mit denselben Parametern ausgeführt werden.
Cache der ersten Ebene:
Hibernate verwendet den Cache der ersten Ebene. Standardmäßig unternehmen Sie nichts, um den Cache der ersten Ebene zu verwenden. Kommen wir direkt zum optionalen Second-Level-Cache. Nicht alle Klassen profitieren vom Caching, daher ist es wichtig, den Second-Level-Cache deaktivieren zu können
Der Hibernate-Second-Level-Cache wird als zweistufiger Prozess eingerichtet. Zunächst müssen Sie sich für die zu verwendende Parallelitätsstrategie entscheiden. Anschließend können Sie den Cache-Ablauf konfigurieren und die physischen Cache-Eigenschaften für die Cache-Bereitstellung verwenden.
Parallelitätsstrategie:
Eine Parallelitätsstrategie ist ein Vermittler, der dafür verantwortlich ist, Datenelemente im Cache zu speichern und aus dem Cache abzurufen. Wenn Sie das Caching der zweiten Ebene aktivieren möchten, müssen Sie für jede Persistenzklasse und Sammlung entscheiden, welche Cache-Parallelitätsstrategie verwendet werden soll.
Transaktional: Verwenden Sie diese Strategie, wenn die hauptsächlich gelesenen Daten darin bestehen, gleichzeitige Transaktionen veralteter Daten zu verhindern, was im seltenen Fall von Aktualisierungen von entscheidender Bedeutung ist.
Lesen/Schreiben: Verwenden Sie diese Strategie erneut, um hauptsächlich Daten zu lesen, bei denen es wichtig ist, im seltenen Fall einer Aktualisierung gleichzeitige Transaktionen aus veralteten Daten zu verhindern.
Nicht striktes Lesen und Schreiben: Diese Strategie garantiert keine Konsistenz zwischen dem Cache und der Datenbank. Die Verwendung dieser Strategie ist nicht kritisch, wenn sich die Daten selten ändern und die Wahrscheinlichkeit veralteter Daten gering ist.
Schreibgeschützt: Die Parallelitätsstrategie gilt für Daten und ändert sich nie. Die Nutzungsdaten dienen nur als Referenz.
Wenn wir für unsere Employee-Klasse Second-Level-Caching verwenden, fügen wir die erforderlichen Zuordnungselemente hinzu, um Hibernate anzuweisen, eine Lese-/Schreib-Caching-Strategie für Employee-Instanzen zu verwenden.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Employee" table="EMPLOYEE"> <meta attribute="class-description"> This class contains the employee detail. </meta> <cache usage="read-write"/> <id name="id" type="int" column="id"> <generator class="native"/> </id> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class> </hibernate-mapping>
Das Attribut „usage="read-write" weist Hibernate an, einen Cache zu verwenden, der durch eine Lese-/Schreib-Parallelitätsstrategie definiert ist.
Cache-Anbieter:
Nachdem Sie über die Parallelitätsstrategie nachgedacht haben, die Ihre Cache-Kandidatenklassen verwenden wird, besteht der nächste Schritt darin, einen Cache-Anbieter auszuwählen. Der Ruhezustand erzwingt die Auswahl eines Caches zur Bereitstellung der gesamten Anwendung.
Cache, der in der angegebenen Konfigurationsdatei hibernate.cfg.xml bereitgestellt wird. Wählen Sie EHCache als Cache-Anbieter der zweiten Ebene:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <!-- Assume students is the database name --> <property name="hibernate.connection.url"> jdbc:mysql://localhost/test </property> <property name="hibernate.connection.username"> root </property> <property name="hibernate.connection.password"> root123 </property> <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> <!-- List of XML mapping files --> <mapping resource="Employee.hbm.xml"/> </session-factory> </hibernate-configuration>
Jetzt müssen Sie die Eigenschaften des Cache-Bereichs angeben. EHCache verfügt über eine eigene Konfigurationsdatei ehcache.xml, die sich im CLASSPATH der Anwendung befindet. Die Cache-Konfiguration der Employee-Klasse in ehcache.xml könnte wie folgt aussehen:
<diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <cache name="Employee" maxElementsInMemory="500" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" />
Jetzt aktivieren Sie den Second-Level-Cache der Employee-Klasse und Hibernate verfügt nun über den Second-Level-Cache, wann immer ein Mitarbeiter durchsucht wird oder Beim Laden von Mitarbeitern nach Kennung.
sollte alle Ihre Klassen analysieren und für jede Klasse die geeignete Caching-Strategie auswählen. Manchmal kann der Second-Level-Cache die Leistung der Anwendung beeinträchtigen. Es wird daher empfohlen, die Anwendung zum ersten Mal ohne aktiviertes Caching zu testen, ideal zum Caching und zur Überprüfung der Leistung. Wenn Caching die Systemleistung nicht verbessert, macht es keinen Sinn, irgendeine Art von Cache zur Verfügung zu stellen.
Caching auf Abfrageebene:
Um den Abfragecache zu verwenden, müssen Sie ihn zunächst in der Konfigurationsdatei mithilfe der Eigenschaft hibernate.cache.use_query_cache="true" aktivieren. Wenn Sie diese Eigenschaft auf „true“ setzen, lässt Hibernate den erforderlichen Cache im Speicher erstellen, um Abfragen und Bezeichnersätze zu speichern.
Als nächstes können Sie zur Verwendung des Abfragecaches die Methode setCacheable(Boolean) der Query-Klasse verwenden. Zum Beispiel:
Session session = SessionFactory.openSession(); Query query = session.createQuery("FROM EMPLOYEE"); query.setCacheable(true); List users = query.list(); SessionFactory.closeSession();
Hibernate也支持通过一个缓存区域的概念非常细粒度的缓存支持。缓存区是这是给定一个名称缓存的一部分。
Session session = SessionFactory.openSession(); Query query = session.createQuery("FROM EMPLOYEE"); query.setCacheable(true); query.setCacheRegion("employee"); List users = query.list(); SessionFactory.closeSession();
此代码使用方法告诉Hibernate来存储和查找在缓存中的员工方面的查询。
Hibernate原生SQL
可以使用原生SQL来表达数据库查询,如果想利用数据库特有的功能,如查询提示或者Oracle中的CONNECT关键字。 Hibernate3.x允许使用手写SQL语句,包括存储过程,所有的创建,更新,删除和load操作。
应用程序将从会话创建一个原生SQL查询(Session接口上)createSQLQuery()方法:
public SQLQuery createSQLQuery(String sqlString) throws HibernateException
当传递一个包含SQL查询到createSQLQuery()方法,可以将SQL结果与任何现有的Hibernate实体,联接,或者一个标量结果使用addEntity()方法,addJoin(),和addScalar()方法关联的字符串。
标量查询:
最基本的SQL查询是从一个或多个表中得到标量(数值)的列表。以下是语法使用原生SQL标量的值:
String sql = "SELECT first_name, salary FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); List results = query.list();
实体的查询:
上面的查询都是返回标量值,也就是从resultset中返回的“裸”数据。以下是语法通过addEntity()方法来从原生SQL查询获得实体对象作为一个整体。
String sql = "SELECT * FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); List results = query.list();
命名SQL查询:
以下是语法通过addEntity()方法来从原生SQL查询获得实体对象和使用命名SQL查询。
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); query.setParameter("employee_id", 10); List results = query.list();
Native SQL 例子:
考虑下面的POJO类:
public class Employee { private int id; private String firstName; private String lastName; private int salary; public Employee() {} public Employee(String fname, String lname, int salary) { this.firstName = fname; this.lastName = lname; this.salary = salary; } public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this.firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this.lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this.salary = salary; } }
让我们创建下面的EMPLOYEE表来存储Employee对象:
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id) );
以下将被映射文件。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Employee" table="EMPLOYEE"> <meta attribute="class-description"> This class contains the employee detail. </meta> <id name="id" type="int" column="id"> <generator class="native"/> </id> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class> </hibernate-mapping>
最后,我们将创建应用程序类的main()方法来运行,我们将使用原生SQL查询的应用程序:
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.SQLQuery; import org.hibernate.Criteria; import org.hibernate.Hibernate; import org.hibernate.cfg.Configuration; public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new Configuration().configure().buildSessionFactory(); }catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Add few employee records in database */ Integer empID1 = ME.addEmployee("Zara", "Ali", 2000); Integer empID2 = ME.addEmployee("Daisy", "Das", 5000); Integer empID3 = ME.addEmployee("John", "Paul", 5000); Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000); /* List down employees and their salary using Scalar Query */ ME.listEmployeesScalar(); /* List down complete employees information using Entity Query */ ME.listEmployeesEntity(); } /* Method to CREATE an employee in the database */ public Integer addEmployee(String fname, String lname, int salary){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } return employeeID; } /* Method to READ all the employees using Scalar Query */ public void listEmployeesScalar( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); String sql = "SELECT first_name, salary FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); List data = query.list(); for(Object object : data) { Map row = (Map)object; System.out.print("First Name: " + row.get("first_name")); System.out.println(", Salary: " + row.get("salary")); } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to READ all the employees using Entity Query */ public void listEmployeesEntity( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); String sql = "SELECT * FROM EMPLOYEE"; SQLQuery query = session.createSQLQuery(sql); query.addEntity(Employee.class); List employees = query.list(); for (Iterator iterator = employees.iterator(); iterator.hasNext();){ Employee employee = (Employee) iterator.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } }
编译和执行:
下面是步骤来编译并运行上述应用程序。请确保在进行的编译和执行之前,适当地设置PATH和CLASSPATH。
执行ManageEmployee二进制文件来运行程序。
会得到以下结果,并记录将在EMPLOYEE表中创建。
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........ First Name: Zara, Salary: 2000 First Name: Daisy, Salary: 5000 First Name: John, Salary: 5000 First Name: Mohd, Salary: 3000 First Name: Zara Last Name: Ali Salary: 2000 First Name: Daisy Last Name: Das Salary: 5000 First Name: John Last Name: Paul Salary: 5000 First Name: Mohd Last Name: Yasee Salary: 3000
如果检查EMPLOYEE表,它应该记录下已:
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+ | id | first_name | last_name | salary | +----+------------+-----------+--------+ | 26 | Zara | Ali | 2000 | | 27 | Daisy | Das | 5000 | | 28 | John | Paul | 5000 | | 29 | Mohd | Yasee | 3000 | +----+------------+-----------+--------+ 4 rows in set (0.00 sec)
更多Ausführliche Erläuterung des Cachings und der Verwendung nativer SQL-Anweisungen im Hibernate-Framework von Java相关文章请关注PHP中文网!