In the previous chapter, if Hibernate is mainly object-oriented and supplemented by links, it focuses on Relational Models in mybatis. In other words, if the object model is poorly designed, it is easy to feel the difficulty of implementation.
First, let's take a look at the simplest one-way many2one:
Object creation:
Public Class Customer {
Private long ID;
Private string name;
}
Public class orders {
Private long ID;
Private string Sn;
Private double price;
Private customer;
}
Orders and customer are a one-way many2one relationship. Like hibernate, let's first configure a simple Customer:
Create customermapper. xml:
<Mapper namespace = "CD. itcast. mybatis. Customer">
<Insert id = "save" keyproperty = "ID" parametertype = "customer"
Usegeneratedkeys = "true">
Insert into customer (name) values (# {name })
</Insert>
<Select id = "get" resulttype = "customer" parametertype = "int">
Select * from customer where ID =#{ ID}
</SELECT>
</Mapper>
It is just a simple single object ing operation.
In hibernate's many2one, we know that the foreign key of the principal is associated with the primary key of one. When the producer saves the data, the ID of the associated one party should be saved in the corresponding foreign key. Therefore, the insert statement stored by the publisher should be as follows:
Ordersmapper. xml:
<Insert id = "save" keyproperty = "ID" parametertype = "orders"
Usegeneratedkeys = "true">
Insert into orders (Sn, price, customer_id) values (# {sn}, # {price}, # {customer. ID })
</Insert>
Here we can see that # {customer. id} to represent the ID attribute of orders's customer attribute. mybatis will automatically help us get the value like El. Therefore, you must pay attention to the order of saving objects here. You must first save one and then save the receiver. In hibernate, if the storage order is incorrect, Hibernate will synchronize dirty data when committing the transaction. It will help us to add an update statement to ensure that the object relationship is correct, but in mybaits, all SQL statements are completed by us, so no one will help us with the update. Therefore, the corresponding save test should be:
@ Test
Public void testsave (){
Sqlsession session = mybatisutil. opensession ();
Customer c = new customer ();
C. setname ("itcast ");
Orders o = new orders ();
O. setprice (800d );
O. setsn ("001 ");
O. setcustomer (C );
Session. insert ("CD. itcast. mybatis. Customer. Save", C );
Session. insert ("CD. itcast. mybatis. Orders. Save", O );
Session. Commit ();
Session. Close ();
}
The following describes how to obtain the signature. If you simply configure orders as a single object, use resulttype to map:
<Select id = "get" parametertype = "long" resulttype = "orders">
Select * from orders where O. ID =#{ ID}
</SELECT>
If so, during the test:
@ Test
Public void testget (){
Sqlsession session = mybatisutil. opensession ();
Orders o = session. selectone ("CD. itcast. mybatis. Orders. Get", 1l );
System. Out. println (O );
Customer C = O. getcustomer ();
System. Out. println (C );
Session. Close ();
}
As you can see, the corresponding customer of orders is null, which only means that mybatis cannot help us automatically complete the related relationship ing. Next let's look at the relationship ing in mybatis:
Method 1: use additional SQL:
<Select id = "get" parametertype = "int" resultmap = "ordersmap">
Select * from orders where O. ID =#{ ID}
</SELECT>
Here, add the resultmap to complete the corresponding ing:
<Resultmap type = "orders" id = "ordersmap">
<ID property = "ID" column = "ID"/>
<Result property = "Sn" column = "Sn"/>
<Result property = "price" column = "price"/>
<Association property = "customer" column = "customer_id" javatype = "customer"
Select = "CD. itcast. mybatis. Customer. Get">
</Resultmap>
It may be strange to see this configuration for the first time. In fact, it is easy to understand:
1. Association: In mybatis, the relationship is not as detailed as in hibernate. For example, one-to-one and one-to-one are divided into two types: the first is the relationship between a single object, and association is used. The other is the relationship of a set, which will be viewed later. Here, orders only uses the customer object as its own attribute, so Association is used to represent this relationship;
2. Property: similar to hibernate, define the corresponding property of this link on the orders object. After the associated object ing is completed, the object will be set to the orders object using this attribute;
3, column: indicates the query result set (select * from orders where id = ?) Columns for maintaining the link. The foreign key customer_id is specified here;
4. javatype: indicates the type of the object to be returned after the ing is completed. Here it must be orders.
5. Select: it is the most critical aspect of this ing method. This select refers to CD. itcast. mybatis. customer. get this SQL statement, which is the SQL statement for obtaining the customer, and this SQL statement requires the input of a customer ID. We have previously specified that the SQL statement should be passed to the CD through column = "customer_id. itcast. mybatis. customer. the get value is the customer_id In the result set.
Therefore, we can see that the mybatis ing method is: first, execute select * from orders where o. id = # {ID}, and then the attributes of ID, Sn, and price are obtained directly from the result set. Then, the value corresponding to the customer_id column is obtained from the result set, this value is the ID of the customer object corresponding to orders, and then the value is assigned to CD as the ID. itcast. mybatis. customer. get is executed, and the execution result is assembled into a customer object, and then the object is set to the customer attribute of orders. Complete the ing.
Run the get test again:
Debug [main]-ooo using connection [[email protected]
Debug [main]-==> preparing: Select * from orders where id =?
Debug [main]-==> parameters: 1 (long)
Trace [main]-<= columns: ID, Sn, cust_id
Trace [main]-<= row: 1,001, 1
Debug [main]-ooo using connection [[email protected]
Debug [main]-==> preparing: Select * from customer where id =?
Debug [main]-==> parameters: 1 (long)
Trace [main]-<= columns: ID, name
Trace [main]-<= row: 1, C
Orders [ID = 1, Sn = 001]
Customer [ID = 1, name = C]
You can see that the query results are normal. However, there may be some questions. When we were learning hibernate, didn't we say that delayed loading is a better way to process objects? But now we can see that the object in the example does not delay loading. By default, mybatis does not delay object loading:
To enable delayed loading, add several configurations to mybatis in the mybatis-config.xml:
<Settings>
<Setting name = "lazyloadingenabled" value = "true"/>
<Setting name = "aggressivelazyloading" value = "false"/>
</Settings>
Run the get test again: the result is the same as that of the previous one, and the system still does not feel the execution of delayed loading. Where is the problem? In fact, mybatis has completed the delayed loading, but the delay loading policy of mybatis is different from that of hibernate. Hibernate makes the loaded target object a proxy object to provide delayed loading (that is, the customer here), and mybatis makes the object itself a delayed loading object. Let's modify the get test:
Sqlsession session = mybatisutil. getinstance (). opensession ();
Ordersmapper om = session. getmapper (ordersmapper. Class );
Orders o = om. Get (1l );
System. Out. println (O. getclass ());
Session. Close ();
Print result:
Debug [main]-ooo using connection [[email protected]
Debug [main]-==> preparing: Select * from orders where id =?
Debug [main]-==> parameters: 1 (long)
Trace [main]-<= columns: ID, Sn, cust_id
Trace [main]-<= row: 1,001, 1
Class CD. itcast. mybatis. domain. Orders $ enhancerbycglib $39a00050
001
As you can see, the orders object is a proxy object, and other properties are accessed without sending SQL. However, as long as the customer is obtained, the SQL statement for querying the customer is immediately sent. In short, the delay loading principle of mybatis is that as long as you get this object, it indicates that you are using this object. Note the differences with hibernate.
The second method is recommended by mybatis. The above method is prone to n + 1 problems. Therefore, we recommend that you use the inline ing method for mybatis. Modify ordersmapping:
<Resultmap type = "orders" id = "ordersmapper">
<ID property = "ID" column = "ID"/>
<Result property = "Sn" column = "Sn"/>
<Association property = "customer" javatype = "customer">
<ID property = "ID" column = "CID"/>
<Result property = "name" column = "cname"/>
</Association>
</Resultmap>
<Select id = "get" resultmap = "ordersmapper" parametertype = "long">
Select C. ID as CID, C. Name as cname, O. * from
Orders o left join customer C on O. cust_id = O. ID where O. ID =#{ ID}
</SELECT>
First, use left join in select to query the orders and the corresponding customer, and set the corresponding alias for the customer.
Second, modify the resultmap, remove select and column, and change it to the internal ing form.
After mybatis executes the SQL statement, it converts the response property to the attribute of the orders object. When it is parsed to the customer property, mybatis converts the columns in the result set to the customer object using the internal ing relationship.
Run get again and the execution results are the same.
Again, we recommend that you use the second method to complete the ing for mybatis. Some people will take it into consideration again. If we only need the orders drop-down list and do not need the customer in the result, isn't this SQL statement a waste of performance? Another principle of mybatis should be mentioned here, which should be configured as needed. This means that, if it is only used as a drop-down list, you only need to make a SELECT statement to filter the drop-down list of orders.