The initial database file required in this article, complete sample code for common Hibernate operations (including all required jar files for Hibernate operations) is provided for download and learning: http://download.csdn.net/detail/daijin888888/9551724
1. Hibernate association mapping
1) What is association mapping?
If there is an association between tables, Hibernate allows us to describe their association in hbm.xml, and then automatically operate on another relationship table according to this relationship when we operate one of the tables. Then, the settings of this association relationship are called association mapping.
2) What are the benefits of association mapping?
Multiple tables can be associated with one visit
--Follow the data of the relationship table associative
--Associate new and modified data of relationship tables
--Associated delete data from the relationship table
3) Association mapping implementation steps
-- Understand the relationship between tables and clarify the relationship fields
--Append the association attribute in the entity class to encapsulate the associated data
--You need to configure hbm.xml file and set the association relationship
*2. One-to-many association
Example: If an Account has multiple Service records, it is hoped that when querying the account data, it will automatically query its corresponding service data.
1) Table relationship
A one-to-many relationship, the relationship field is service.account_id. (That is, there must be a field account_id associated with the Account table in the Service table, and this field corresponds to the id in the Account table)
2) Append relationship attributes
In the Account class, append the associated attribute services, which is type Set<Service>.
private Set<Service> services = new HashSet<Service>();
3) Set up relationships
--grammar
Set a one-to-many relationship in Account.hbm.xml
<set name="association attribute name"> <key column="association field name"/> <one-to-many/> </set> --Implement <set name="services"> <key column="account_id"/> <one-to-many/> </set>
4) Sample code
Known:
--Associated attribute services
--Associated field account_id
--Association Object Service --> Table Name Service
<span style="font-size:14px;">public void testFind() { Session session = HibernateUtil.getSession(); Account a = (Account) session.load(Account.class, 1010); System.out.println("---Show Account account information----"); System.out.println(a.getId() + " " + a.getRealName() + " " + a.getIdcardNo()); System.out.println("--Show the business account under the current account----"); Set<Service> services = a.getServices(); for (Service s : services) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } System.out.println(a.toString()); }</span>*3. Many-to-one association
Example: I hope that after querying service data, I can automatically query its corresponding account data.
1) Relationship
service and account have a many-to-one relationship, and the relationship field is service.account_id
2) Append the associated attributes
--Append the associated property account in the Service entity class, its type is Account.
private Account account;
After that, the accountId attribute can be removed, and the value of account_id can be obtained through the getAccount().getId() method
3) Set up relationships
a. Syntax:
--In Service.hbm.xml, add the configuration of the association relationship
--<many-to-one name="association attribute name"
column="Relational field name"
/>
b. Implementation:
<many-to-one name="account"
column="account_id"
/>
4) Sample code
Known:
--Association property account
--Associated field account_id
--Account --> Table name account, primary key id
<span style="font-size:14px;">public void testFind() { Session session = HibernateUtil.getSession(); Service s = (Service) session.get(Service.class, 2002); System.out.println("----Show business account information----"); System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); System.out.println("---Show related account information---"); System.out.println(s.getAccount().getId() + " " + s.getAccount().getRealName()); }</span>*4. Related operations
1) Related query
If you need to use an SQL statement to instantiate the current object and the associated attribute, you can use the following method:
a. (Not recommended) Modify the associated attribute mapping in hbm.xml
lazy attribute:
true means that lazy loading is enabled;
false means closing lazy loading
fetch attribute:
Join means that the connection method is used to query with the main object. At this time, lazy="false" is invalid;
select (default) means sending a SQL query associated data separately
b. (Recommended) Pass HQL and join fetch syntax
--from Account a join fetch a.services where a.id=?
Meaning: When querying Account object, the services associated attribute data are found together using table connection.
--from Service s join fetch s.account where s.id=?
Meaning: When querying Service objects, the account associated attribute data is found together using table connection.
--from Service s join fetch s.account where s.account.id=?
Notice:
-- The objects and properties are written in HQL
--join fetch has no on clause after it, and fetch is associated attribute
--query.setInteger to set the integer parameter value, and the subscript starts from 0.
--If it is clear that the HQL will only return one record, you can use the query.uniqueResult() method to return a unique record
c. Sample code (rewrite the above one-to-many association query code)
<span style="font-size:14px;">public void testFind() { Session session = HibernateUtil.getSession(); // Account a = (Account) session.load(Account.class, 1010); String hql = "from Account a join fetch a.services where a.id=?"; Query query = session.createQuery(hql); query.setInteger(0, 1010);// ?Start from 0 Account a = (Account) query.uniqueResult();// Single-line query can use System.out.println("---display Account information----"); System.out.println(a.getId() + " " + a.getRealName() + " " + a.getIdcardNo()); System.out.println("---display the business account under the current account----"); Set<Service> services = a.getServices(); for (Service s : services) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } System.out.println(a.toString()); }</span> 2) Cascading addition and cascading modification
a. When a table has an association relationship, Hibernate not only provides the function of association query, but also has the ability to add, modify, and delete data in the association table. This ability is called cascading operation.
b. How to implement cascading operations
You need to add the attribute cascade at the location where the associated attribute is set.
--none: Cascading is not supported by default
--save-update: Supports cascading addition and update
--delete: Supports cascading deletion
--all: Supports cascading addition, update, and delete
c. Description
Usually, there is a 1-to-many table relationship. One side of 1 is the main table and the other side of 1 is the slave table. It is often necessary to add, update, and delete the slave table data when adding, updating, and deleting the main table. For example: When deleting an account, you must delete the data of the business account together.
3) Cascade deletion
a. Set cascade="delete" or cascade="all" to support cascade deletion
b. Generally, it is necessary to add the attribute inverse="true" at the set tag of 1.
c. session.delete(obj);obj needs to be a persistent object, cannot be new, and needs to be load/get to be retrieved.
d. Methods for batch deletion:
Cascading delete uses n+1 delete statements to clear the associated data of the main table and foreign key table.
If it is batch deletion , cascading deletion is not recommended. It is recommended to use HQL to write delete delete statements .
delete from Service where account.id=?//Delete all data of account.id=? in the Service table, (this sentence replaces n delete statements in the cascading operation)
delete from Account where id=?
4) Inverse attribute (understanding) details here
Whether to hand over control of relationship maintenance. That is, by default, the relationship between the Account and Service objects is maintained by both parties. It means that when doing cascading operations on Account or Service objects, you need to execute an update statement to set the associated field to the same ID. If you need to cancel the relationship maintenance work of a certain party, you can add inverse="true" setting to the associated attributes section, which can avoid the execution of the update statement.
true: hand over control, the current object is not responsible for maintaining the relationship between the two tables
false: The control is not handed over, the current object must be responsible for maintaining the relationship between the two tables
Tip: It is often set to inverse="true" for one party (i.e., the <one-to-many> mapping part) to inverse="true", so that a large number of update update statements can be avoided when cascading operations on one party.
*5. Many-to-many association
Example: Admin admin_info and role role_info have a many-to-many relationship. I hope that when querying the administrator, he can query his corresponding role. When designing a database, it is necessary to use 3 tables to represent it.
ADMIN_INFO (Admin)
ADMIN_ROLE (Admin and Role Relationship)
ROLE (role)
1) Relationship fields
The relationship fields are located in their intermediate table admin_role,
admin_id=admin_info.id
role_id=role_info.id
2) Append the associated attributes Append the role-related attributes to the administrator's entity class
Set<Role> roles
3) Append the association mapping configuration in Admin.hbm.xml
--Syntax<set name="association attribute name" table="middle table name"> <key column="Admin's associated field name"/> <many-to-many column="Admin's associated field name"/> </set> --Code<set name="roles" table="admin_role"> <key column="admin_id"/> <many-to-many column="role_id"/> </set>
4) Cascade operation
cascade means that cascade operations are supported, and the table operates on the other side, rather than representing the intermediate table of cascade operations. For the maintenance of intermediate tables, there is no need to write the cascade attribute.
5) inverse
Generally speaking, many-to-many relationships do not need to write inverse="true". The reason is that when the other party inserts data, it may not have the data in the intermediate table, and the current party needs to maintain it. Therefore, inverse="true" cannot be written. Otherwise, neither party maintains this relationship and there are problems with the data.
6) Sample Java code
<span style="font-size:14px;"> // Remove role @Test public void testDeleteRole() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); try { Admin a = (Admin) session.load(Admin.class, 1); Role r1 = (Role) session.load(Role.class, 1); a.getRoles().remove(r1); session.update(a); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); tx.rollback(); } finally { session.close(); } } // Append role @Test public void testAddRole() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); try { Admin a = (Admin) session.load(Admin.class, 1); Role r1 = (Role) session.load(Role.class, 1); Role r2 = (Role) session.load(Role.class, 43); Role r3 = (Role) session.load(Role.class, 44); a.getRoles().add(r1); a.getRoles().add(r2); a.getRoles().add(r3); session.update(a); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); tx.rollback(); } finally { session.close(); } } @Test public void testFind() { Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); try { Admin a = (Admin) session.load(Admin.class, 1); System.out.println("-----Show administrator information----"); System.out.println(a.getId() + " " + a.getName() + " " + a.getTelephone()); System.out.println("----Show administrator role information---"); for (Role role : a.getRoles()) { System.out.println(role.getName() + " "); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); tx.rollback(); } finally { session.close(); } }</span>6. Inheritance association
Example: Search for products on e-commerce websites, such as entering iPhone to search. The search results can include product information related to mobile phones, mobile phone films, mobile phone cases, chargers, headphones, etc. This function can be expressed by a special one-to-one relationship when designing tables. That is, the common attributes of all products are extracted into a common table product. Only the specific product table is stored in the specific product table, so the specific product table and the product table have a one-to-one relationship. When searching, you can only search for the product table, and you can fuzzy search for relevant information.
--General information table product(id, name, price, desc)
--book product list book(id,authod,publishing,words)
--I hope that when operating the book table, I can automatically maintain common fields into the product table.
1) Clear relationship
Books and product have a one-to-one relationship. The purpose of this relationship is to reuse fields in the product table, such as an inheritance relationship.
2) Entity Class
Book extends Product
3) Related relationships are reflected in configuration files
--The parent type is consistent with the original configuration file writing method
--Subtypes have special characteristics
<joined-subclass name="type name" table="table name" extends="parent class name"> <key column="association field name"/> <property name="" type="" column=""/> ... </joined-subclass>
4) In the inheritance relationship, since the two tables have a relationship similar to that of a parent and child, the data in the parent table must be referenced in the child table. There is no case of non-reference, that is, the parent table must be maintained while maintaining the child table. So this is a fixed situation, so you don’t need to write cascade or inverse.
5) Description Category (understand)
<joined-subclass>The database has parent class table and child class table
<union-subclass>The database has a subclass table and no parent class table (the subclass table already contains the parent class table field, no parent class table, but has parent class entity object)
<subclass> The database has parent class and child class and uses a table (the design is messy, that is, there is no table splitting, and it is rarely used)
*7. Hibernate query
1) *HQL query (Hibernate Query Language)
It belongs to an object-oriented query statement, querying the POJO mapped by Hibernate, thereby realizing querying the database.
a. Use non-primary key to make conditional query
--conditional parameters to? Indicates that query.setString(0,"");
--The conditional parameters are represented by: x, query.setString("x","");
Sample code:
<span style="font-size:14px;"> // Test to query conditionally by non-primary key @Test public void testFind1() { String hql = "from Service where account.id=? and unixHost=?"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); query.setInteger(0, 1011); query.setString(1, "192.168.0.23"); List<Service> list = query.list(); for (Service s: list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); } // is equivalent to testFind1, using ":identifier" instead of @Test public void testFind2() { String hql = "from Service where account.id=:aid and unixHost=:host"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); query.setInteger("aid", 1011); query.setString("host", "192.168.0.23"); List<Service> list = query.list(); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); }</span> b. Only query some attributes
--The default returned collection encapsulated is Object[]
--new Service(id,unixHost,osUserName) encapsulates the service object in the returned combination.
Notice:
A constructor that needs to append a response in the Service;
Don't throw away the parameterless constructor;
Sample code:
<span style="font-size:14px;"> // Get some field results, and use Object[] to encapsulate data by default @Test public void testFind3() { String hql = "select s.id,s.unixHost,s.osUserName from Service s where s.account.id=?"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); query.setInteger(0, 1011); List<Object[]> list = query.list(); for (Object[] objs : list) { System.out.println(objs[0] + " " + objs[1] + " " + objs[2] + " "); } session.close(); } // equivalent to testFind3, you need to add the corresponding constructor @Test public void testFind4() { String hql = "select new Service(s.id,s.unixHost,s.osUserName) from Service s where s.account.id=?"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); query.setInteger(0, 1011); List<Service> list = query.list(); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); }</span> c. HQL definition is in the configuration file (just understand)
--Define HQL in configuration file through query element
--query element is written behind the class
--session.getNamedQuery(HQL name);
Sample code: <query/> and <class/> are placed in hbm.xml at the same level
<span style="font-size:14px;"><query name="findAll"><!-- Include plain text fields in CDATA to prevent special characters--> <![CDATA[ from Service ]]> </query></span> <span style="font-size:14px;"> // Define HQL into hbm.xml (only static HQL statement structure is applicable) @Test public void testFind5() { Session session = HibernateUtil.getSession(); // Get the hql statement defined in <query> in hbm.xml Query query = session.getNamedQuery("findAll"); List<Service> list = query.list(); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); }</span> d. Pagination query
--Query records
query.setFirstResult((page-1)*pageSize);
query.setMaxResults(pageSize);
--Query the total number of pages
select count(*) from Service
Sample code:
<span style="font-size:14px;"> // Test paging query @Test public void testFind6() { int page = 2; String hql = "from Service order by id"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); // Add paging parameters to set query.setFirstResult((page - 1) * 3);// Set the starting point for grabbing records, starting from 0 query.setMaxResults(3);// Set the maximum number of crawls List<Service> list = query.list();// Execute the query, if there is no pagination setting, check all values for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); } // select count(*) from SERVICE @Test public void testFind7() { String hql = "select count(*) from Service"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); Long size = (Long) query.uniqueResult(); System.out.println("Total number of records:" + size); session.close(); }</span> e. Related query (just remember one)
--from Service s,Account a
where s.account.id=a.id
--from Service s inner join s.account a
--select s.account.realName from Service s
Summarize:
The similarities between HQL and SQL :
--Support select,from,where,group,order by clause
--Support inner join, left join and other connections
--Support >,<,>=,<=,in,not in,between,like and other conditions
--Support grouping statistics functions count,sum,max,min,avg
The differences between HQL and SQL :
--HQL statements are case sensitive, that is, case sensitive. Keywords are indistinguishable.
--HQL writes object names and attribute names, not table names and field names
--The on clause in join on is not supported
--Select is not supported *
--Domain functions are not supported, such as date function to_date(), character function to_char(), etc.
2) Criteria query (not intuitive enough, just understand)
Use Hibernate API to spell a HQL
Criteria c = session.createCriteria(Service.class);
Sample code:
<span style="font-size:14px;"> // Use Hibernate's API to spell an HQL @Test public void testFind1() { Session session = HibernateUtil.getSession(); Criteria c = session.createCriteria(Service.class); c.add(Restrictions.and(Restrictions.like("osUserName", "huang%"), Restrictions.eq("unixHost", "192.168.0.26")));// Append query conditions List<Service> list = c.list();// Execute the query, if there is no pagination setting, check all values c.addOrder(Order.desc("id"));// Append sort// c.setFirstResult(arg0);// Pagination// c.setMaxResults(arg0); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName() + " " + s.getUnixHost()); } session.close(); }</span> 3) SQL query
Directly help us call JDBC to execute SQL queries
SQLQuery sqlQuery = session.createSQLQuery(sql);
Sample code:
<span style="font-size:14px;"> @Test public void testFind1() { String sql = "select * from Service"; Session session = HibernateUtil.getSession(); SQLQuery sqlQuery = session.createSQLQuery(sql); sqlQuery.setFirstResult(0);// Pagination sqlQuery.setMaxResults(3); // By default, an array is used to encapsulate a record List<Object[]> list = sqlQuery.list(); for (Object[] objs : list) { System.out.println(objs[0] + " " + objs[2]); } session.close(); } //Same as testFind1(), specify the entity that encapsulates the record @Test public void testFind2() { String sql = "select * from Service"; Session session = HibernateUtil.getSession(); SQLQuery sqlQuery = session.createSQLQuery(sql); sqlQuery.setFirstResult(0);// Pagination sqlQuery.setMaxResults(3); // Specify the entity class that encapsulates the record sqlQuery.addEntity(Service.class); // Encapsulate a record with the specified Service type List<Service> list = sqlQuery.list(); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName()); } session.close(); }</span>8. Hibernate Advanced Features (Understanding)
1) Level 2 cache
a. Level 2 cache (default off)
--The second-level cache is a SessionFactory-level cache, which is managed by the SessionFactory
--The cached object is also an entity object
--Cached data can be shared between different sessions
--Applicable environment: frequently shared object data; small frequency of change of object data
b. Steps for using Level 2 cache
--Dire cache package ehcache.jar
--Import cache configuration file ehcache.xml
--In hibernate.cfg.xml, set to enable the secondary cache and set the cache driver class
<span style="font-size:14px;"><!-- Using Level 2 Cache--> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- Specify the driver class ehcache.jar --> <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property></span>
--Set the element in the relational mapping file hbm.xml of the POJO to be cached <cache usage="readonly"/>
Sample code:
<span style="font-size:14px;"><span style="font-size:14px;"> @Test public void testFind1() { // For the first query, use session1 Session session1 = HibernateUtil.getSession(); Service s1 = (Service) session1.get(Service.class, 2002); System.out.println(s1.getOsUserName() + " " + s1.getUnixHost()); session1.close(); // The second query uses session2 (after configuring the secondary cache, both queries go to the secondary cache to fetch data) // HibernateUtil.getSessionFactory().evict(Service.class);// After removal, you still query twice. Session session2 = HibernateUtil.getSession(); Service s2 = (Service) session2.get(Service.class, 2002); System.out.println(s2.getOsUserName() + " " + s2.getUnixHost()); }</span></span> 2) Query cache
a. Query cache
Level 1 and Level 2 caches can only cache single objects. If you encounter a string result, array result, or List collection, you can use the query cache storage.
--It can be regarded as a special level 2 cache
--The cache space used is the second-level cache
--The cache is the data type other than the entity object
--Rely on Level 2 cache, it is turned off by default, and Level 2 cache must be turned on before it can be used.
b. Use steps
--Open Level 2 cache
--Set open query cache in hibernate.cfg.xml
<span style="font-size:14px;"><!-- Turn on query cache--> <property name="hibernate.cache.use_query_cache">true</property></span>
Before querying --query.list(), query.setCacheable(true);
c. Usage environment
--The same query statement that needs to be executed frequently
--The query result set content changes frequency small
--Don't have too much data in the result set. Tip: For the same SQL, go to the database for the first time to query, and get out of the cache several times in the future. Because the content of SQL+ result set is cached
Sample code:
<span style="font-size:14px;"><span style="font-size:14px;"> @Test public void testFind() { find(); System.out.println("-------"); find(); } private void find() { String hql = "from Service where account.id=?"; Session session = HibernateUtil.getSession(); Query query = session.createQuery(hql); query.setInteger(0, 1011); // Enable query cache execution query.setCacheable(true); List<Service> list = query.list(); for (Service s : list) { System.out.println(s.getId() + " " + s.getOsUserName()); } }</span></span>9. Hibernate concurrent processing-locking
For example:
Simulate the 12306 ticket purchase mechanism, assuming there is currently a ticket ticket (id, line, amount, version) of train tickets, and simulate the scenario where multiple people purchase tickets at the same time.
1) Pessimistic lock
--The program is pessimistic that every visitor has a concurrency problem, so each piece of data will be locked. Then, only when the current visitor holding the lock releases the lock, the next visitor can access the data. This mechanism is called a pessimistic lock.
--That is, you must lock a data no matter what, regardless of whether the data will have concurrency.
--Features
Low efficiency and high safety
--accomplish:
get(Class,id,LockMode.UPGRADE)
select * from emp for update
Note: Here we use the for update clause that comes with the database for locking, not the locking mechanism invented by Hibernate itself.
2) Optimistic lock
--The program is optimistic that every visitor will not have concurrent problems, so it does not add locks. Instead, when the data is updated, it is determined whether the version of the data has changed. If it changes, it means that there is concurrent occurrence during this period. Therefore, an error is reported and the update failed.
--With the help of the version field, when the first user updates and submits, Hibernate will update the field by 1, so that the object version field submitted by the subsequent user is smaller than that in the database, that is, when the version is found to change during update, an exception will be thrown and the update will fail.
--One success, others failure
--Features
High efficiency, poor user experience
--accomplish
a. You need to append the version field to the table to record the version of the data;
b. Append version attributes to the entity class;
c. The configuration of the additional version in hbm.xml <version name="" type="" column="">
3) How to choose
--If the concurrency is large, optimism lock should be selected
--If the concurrency is small, you should choose pessimistic lock
The above is the comprehensive analysis of Hibernate related operations, query operations, advanced features, and concurrency processing mechanism introduced by the editor to you. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply you in time. Thank you very much for your support to Wulin.com website!