3. MyBatis Loading Strategy and Comment Development

I. MyBatis Loading Policy 1. What...
1. What is delayed loading?
2. Implement local delayed loading
3. Implement global delayed loading
1. Why use caching?
2. Level 1 Cache
3. Secondary Cache
4. Analysis of Secondary Cache
5. Serious problems with secondary caches (dirty reads)
6. Summary
1. Common Notes for MyBatis
2.MyBatis annotation development for deletion and addition
3.MyBatis annotation development for complex mapping development
4.MyBatis annotation development for one-to-one query
5.MyBatis annotation development for one-to-many queries
6.MyBatis annotation development for many-to-many queries
7.MyBatis annotation development for secondary caching
8.MyBatis Annotation Development for Delayed Loading Strategy
9. Summary
I. MyBatis Loading Policy

1. What is delayed loading?

Problem: Configuration and implementation of one-to-one, one-to-many, many-to-many relationships in Mybatis is achievable
Object's associated query. Many times in the actual development process we don't always need to load user information before we have to load his order information. This is what we call delayed loading.
Raise a chestnut

In one-to-many, when we have a user, it has 100 orders Do you want to check out the associated orders when querying the user? Do you want to check out the associated users when querying for orders? A: When querying the user, the order placed by the user should be when to use and when to query. When querying an order, the user information that the order belongs to should be queried along with the order.

**Delayed Loading: ** Loading is done when data is needed and not when data is not needed. Delayed loading is also known as lazy loading

Advantage: Query from a single table first, and then associate queries from related tables when needed, which greatly improves database performance because querying a single table is faster than querying multiple tables from an association. Disadvantages: Because database queries only occur when data is needed, this can cause users to wait longer and experience less when querying large amounts of data because queries also take time. In multiple tables One-to-many, many-to-many: Delayed loading is usually used One-on-one(Many-to-one): Usually immediate loading is used Be careful: Delayed loading is based on nested queries Difference: When the current object and its associated objects are loaded: If its associated object is immediately queried for the current object, it is immediately loaded. Delayed loading occurs when an associated object is looked up;

2. Implement local delayed loading

2.1 Local Delayed Loading

Both association s and collection s tags have a fetchType attribute whose value can be modified to modify local loading policies.

<!--One-to-many nested query: Query all users and at the same time query the orders they have--> <!-- Delayed loading is based on nested queries --> <resultMap id="userMap2" type="user"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="birthday" column="birthday"/> <result property="sex" column="sex"/> <result property="address" column="address"/> <!-- fetchType="lazy" Represents a delayed load policy fetchType="eager" Represents an immediate load policy --> <collection property="ordersList" ofType="orders" fetchType="lazy" select="cn.xuguowen.mapper.OrdersMapper.findById" column="id"/> </resultMap> <select id="findAllWithOrders2" resultMap="userMap2"> select * from user </select>

2.2 Setting the method to trigger delayed loading

I found that after configuring the delayed loading policy, I found that even if no method of the associated object was called, queries of the associated object would be triggered when you called the equals, clone, hashCode, toString methods of the current object.
We can override these four methods in the core configuration file using the lazyLoadTriggerMethods configuration item.

<!--Set method to trigger delayed load policy--> <settings> <!--When the current object's toString()Method uses a delayed load policy--> <setting name="lazyLoadTriggerMethods" value="toString()"/> </settings>

3. Implement global delayed loading

The setting s tag can be used in the core configuration file of MBatis to modify the global loading policy.

<settings> <!--When the current object's toString()Method uses a delayed load policy--> <setting name="lazyLoadTriggerMethods" value="toString()"/> <!--Global Delayed Loading Policy--> <setting name="lazyLoadingEnabled" value="true"/> </settings>

Note that local loading policies take precedence over global ones

<!-- A one-to-one nested query queries all orders while also querying the user information to which each order belongs--> <!-- Turn off global delay loading policy and use immediate loading policy --> <resultMap id="ordersMap2" type="orders"> <id property="id" column="id"/> <result property="ordertime" column="ordertime"/> <result property="total" column="total"/> <result property="uid" column="uid"/> <!--Write here: Consider the second time sql How query statements are introduced, And the first one will be sql Statement queried uid Pass as a parameter to the next day sql In statement Use select Introduce Article 2 sql Statement: Value is second sql Statement's statementid Use column Label will query above uid Pass as a parameter to Article 2 sql In statement --> <association property="user" javaType="user" fetchType="eager" select="cn.xuguowen.mapper.UserMapper.findById" column="uid"/> </resultMap> <select id="findAllWithUser2" resultMap="ordersMap2"> <!-- Note that the return result type cannot be used resultType Automatically encapsulate query results, because Orders There is also an attribute in the entity class user --> select * from orders </select>
2. MyBatis Cache

1. Why use caching?

When users frequently query certain fixed data, they query the data from the database for the first time and save it in the cache. When users query the data again, they do not need to query through the database anymore, but query inside the cache. Reduce the wastage caused by network connections and database queries, which improves our query efficiency.Reduce system performance problems caused by high concurrent access.
One sentence summary: Query frequently for data that does not change frequently, and use caching to improve query efficiency.
Like most persistence frameworks, Mybatis also provides a caching strategy that improves performance by allowing a small number of queries to the database. Caches in Mybatis are divided into first-level caches and second-level caches.

2. Level 1 Cache

Level 1 cache is a SqlSeesion level cache and is turned on by default
So when the parameters and SQL statements are exactly the same, we use the same SqlSession object to invoke a Mapper method, often only execute SQL once, because after the first query with SelSession, MyBatis puts it in the cache, and when we query later, SqlSession takes out the current one if no refresh is declared and the cache has not timed outCached data without sending SQL to the database again.

@Test public void testOneCache() throws IOException { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = factory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); // First Query User user1 = mapper.findById(1); System.out.println(user1); // Second Query User user2 = mapper.findById(1); System.out.println(user2); }


Note that first-level caches are SqlSession-wide caches. Performing C (increase) U (update) D (delete) operations for SqlSession or calling clearCache(), commit(), close() methods will empty the cache and avoid dirty reads.

Cache is cleared for each query

<select flushCache="true"></select>

3. Secondary Cache

The secondary cache is a namspace level (cross sqlSession) cache and is not enabled by default
The opening of the secondary cache needs to be configured. When implementing the secondary cache, MyBatis requires that the POJO returned be serializable. That is, it requires the Serializable interface to be implemented. The configuration method is simple and requires only mapping the XML file configuration to open the secondary cache.

Core Profile
<settings> <!-- 1.name="cacheEnabled" Represents a secondary cache, and the default value is true, 2.value="true" Indicates opening a secondary cache --> <setting name="cacheEnabled" value="true"/> </settings>
Configure UserMapper.xml file
<!--Current mapping profile opens secondary cache--> <cache></cache> <!-- useCache="true" Represents the current UserMapper Using a secondary cache --> <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = # </select>
Modify User Entity
public class User implements Serializable { private Integer id; private String username; private Date birthday; private Character sex; private String address; // Relationships that represent many: A list of orders the current user has private List<Orders> ordersList; // Many Relationships: A list of roles the current user has private List<Role> roleList;
test result
/** * Verify Level 2 Cache * @throws IOException */ @Test public void testTwoCache() throws IOException { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession1 = factory.openSession(); UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1); // Only when SqlSession.commit() or SqlSession.close is executed will the contents of the first level cache be flushed to the second level cache sqlSession1.close(); SqlSession sqlSession2 = factory.openSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.findById(1); System.out.println(user2); sqlSession2.close(); }

4. Analysis of Secondary Cache

5. Serious problems with secondary caches (dirty reads)

**The secondary cache of mybatis has dirty read problems when querying multiple tables because it is namespace level
**

6. Summary

1. mybatis All caches do not require us to store and retrieve data manually. mybatis Maintained automatically. 2. mybatis When the secondary cache is turned on, the query order is: the secondary cache-->Level 1 Cache-->data base 2. Be careful: mybatis Second-level caches can have dirty reading problems and need to be solved using third-party caching technology.
3. MyBatis Annotation Development

1. Common Notes for MyBatis

* @Insert: Achieve additions instead of<insert></insert> * @Delete: Delete instead<delete></delete> * @Update: Implement updates instead<update></update> * @Select: Implement the query instead<select></select> * @Result: Implement result set encapsulation instead<result></result> * @Results: Can be used with@Result Use together to encapsulate multiple result sets instead<resultMap></resultMap> * @One: Implement one-to-one result set encapsulation instead<association></association> * @Many: Implement one-to-many result set encapsulation instead<collection></collection>

2.MyBatis annotation development for deletion and addition

1: UserMapper interface

package cn.xuguowen.mapper; import cn.xuguowen.pojo.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; /** * @author Xu Guowen * @create 2021-10-03 17:40 */ public interface UserMapper { /** * Query all user information * @return */ @Select("select * from user") List<User> findAll(); /** * Save user information * @param user */ @Insert("insert into user (username,birthday,sex,address) values (#, #, #,# )") void save(User user); /** * Modify user information based on user id * @param user */ @Update("update user set username = #,birthday = # where id = #") void update(User user); /** * Delete users based on id * @param id */ @Delete("delete from user where id = #") void delete(Integer id); }

Core Profile

<!--We used a mapping file that was replaced by annotations, so we just need to load the one that used annotations Mapper Interface is sufficient--> <mappers> <!--Scan using annotated Mapper class--> <!-- <mapper></mapper> --> <!--Scan using annotated Mapper The package in which the class resides--> <package name="com.lagou.mapper"></package> </mappers>

3: Testing

package cn.xuguowen.test; import cn.xuguowen.mapper.UserMapper; import cn.xuguowen.pojo.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; /** * @author Xu Guowen * @create 2021-10-03 17:42 */ public class TestAnno { private SqlSessionFactory factory; private SqlSession sqlSession; @Before public void before() throws IOException { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); sqlSession = factory.openSession(); } @After public void after() { sqlSession.commit(); sqlSession.close(); } @Test public void testFindAll() throws IOException { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.findAll(); for (User user : users) { System.out.println(user); } } @Test public void testSave() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setUsername("Xu Guowen"); user.setBirthday(new Date()); user.setSex('male'); user.setAddress("Datong, Shanxi"); mapper.save(user); } @Test public void testUpdate() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setUsername("Boss Huang"); user.setBirthday(new Date()); user.setId(6); mapper.update(user); } @Test public void testDelete() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.delete(8); } }

3.MyBatis annotation development for complex mapping development

Previously, we implemented complex relationship mapping in the mapping file by configuring resultMap, association, collection.
After developing with annotations, we can use @Results, @Result, @One, @Many annotations to configure complex relationships

annotationExplain@ResultsThe replacement tag is resultMap, which can use either a single @Result annotation or a @Result collection. Use the format: @Results({@Result(),@Result(),@Result(),@Result(), @Result(), @Result()})@ResultInstead of label id and result. @Result property description: column: column: column name of database, property needs to be assembled property name, one needs to use @One annotation (@Result(one=@One())), man needs @Many annotation (@Result(many=@Many()))@One (one-to-one)Replacing the associations tag is the key to a multitable query and is used in the annotation to specify that the subquery returns a single object. @One annotation property description: select specifies the sql mapper used for the query, which is essentially namespace.id to determine which sql statement is in which mapper. Use format: @Result(column=", property=", "one=@One(select=")@Many (one-to-many)Replacing the collection tag is the key to a multitable query and is used in the comment to specify the set of objects returned by the subquery. Use the format: @Result(property=", column=", many=@Many(select=")

4.MyBatis annotation development for one-to-one query

4.1 Requirement: Query order information and at the same time query the user information to which the order belongs

One-to-one Query Statement
SELECT * FROM orders; SELECT * FROM `user` WHERE id = #;

4.2 Code implementation

a) OrderMapper interface and UserMapper interface
/** * Query all orders and at the same time query the user information to which the order belongs * @return */ @Select("select * from orders") @Results({ @Result(property = "id",column = "id"), @Result(property = "ordertime",column = "ordertime"), @Result(property = "total",column = "total"), @Result(property = "uid",column = "uid"), @Result(property = "user",javaType = User.class,column = "uid", one = @One(select = "cn.xuguowen.mapper.UserMapper.findById", fetchType = FetchType.EAGER)) }) List<Orders> findAllWithUser();
/** * Annotations implement one-to-one queries: query all orders and the user information to which the order belongs * @param uid * @return */ @Select("select * from user where id = #") User findById(Integer uid);
b) Test code
/** * Test one-to-one query: query all orders and the user information to which the order belongs */ @Test public void testOneToOne() { OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Orders> allWithUser = mapper.findAllWithUser(); for (Orders orders : allWithUser) { System.out.println(orders); } }

5.MyBatis annotation development for one-to-many queries

5.1 Requirements: Query all users and the order information they have

One-to-many query statement
SELECT * FROM user; SELECT * FROM `orders` WHERE uid = #;

5.2 Code implementation

a) UserMapper interface and OrdersMapper interface
/** * Annotations implement one-to-many queries: query all users and find out what order information they have * @return */ @Select("select * from user") @Results({ @Result(property = "id",column = "id",id = true), @Result(property = "username",column = "username"), @Result(property = "birthday",column = "birthday"), @Result(property = "sex",column = "sex"), @Result(property = "address",column = "address"), @Result(property = "ordersList",javaType = List.class,column = "id", many = @Many(select = "cn.xuguowen.mapper.OrderMapper.findById") ) }) List<User> findAllWithOrders();
/** * Annotations implement one-to-many queries: query all users and find out what order information they have * @param uid Query out the order information the user has based on the user id * @return */ @Select("select * from orders where uid = #") List<Orders> findById(Integer uid);
b) Test code
/** * Test a one-to-many query: query all users and the order information they have */ @Test public void testOneToMany() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.findAllWithOrders(); for (User user : users) { // In the core configuration file: Configured to trigger the delayed load policy when the toString() method of the current object is called System.out.println(user); // Now I need to query the user's order information System.out.println(user.getOrdersList()); } }

6.MyBatis annotation development for many-to-many queries

6.1 Requirement: Query all users and all roles of that user at the same time

Many-to-Many Query Statement
SELECT * FROM user; SELECT * FROM sys_role r INNER JOIN sys_user_role ur ON r.id = ur.roleid WHERE ur.userid = #;

6.2 Code implementation

a) UserMapper interface and RoleMapper interface
/** * Annotations enable many-to-many queries: query all users and the role information they have * @return */ @Select("select * from user") @Results({ @Result(property = "id",column = "id",id = true), @Result(property = "username",column = "username"), @Result(property = "birthday",column = "birthday"), @Result(property = "sex",column = "sex"), @Result(property = "address",column = "address"), @Result(property = "roleList",javaType = List.class,column = "id", many = @Many(select = "cn.xuguowen.mapper.RoleMapper.findByUserId")) }) List<User> findAllWithRole();
/** * Annotations enable many-to-many queries: query all users and the role information they have * @param uid Query user's role information based on user id * @return */ @Select("SELECT * FROM sys_role r INNER JOIN sys_user_role ur ON r.id = ur.roleid WHERE ur.userid = #") List<Role> findByUserId(Integer uid);
b) Test code
/** * Annotations enable many-to-many queries: query all users and the role information they have */ @Test public void testManyToMany() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.findAllWithRole(); for (User user : users) { // Because a global delayed loading policy is set in the core configuration file: the delayed loading mechanism is triggered when the current object toString() method is called System.out.println(user); System.out.println(user.getRoleList()); } }

7.MyBatis annotation development for secondary caching

7.1 Configure Core Profile Support for Opening Secondary Cache

<settings> <!-- 1.name="cacheEnabled" Represents a secondary cache, and the default value is true, 2.value="true" Indicates opening a secondary cache --> <setting name="cacheEnabled" value="true"/> </settings>

7.2 Configuring a secondary cache using annotations in the Mapper interface

/*Use the @CacheNamespace annotation for secondary caching*/ @CacheNamespace public interface UserMapper {...}

8.MyBatis Annotation Development for Delayed Loading Strategy

Whether one-to-one or one-to-many, there is a fetchType attribute in the annotation configuration

* fetchType = FetchType.LAZY Indicates lazy loading * fetchType = FetchType.EAGER Indicates immediate loading * fetchType = FetchType.DEFAULT Indicates use of global configuration,If the value of the global delay loading policy is true,Indicates the use of a delayed load policy; if the value of the global delayed load policy is false,Indicates the use of the immediate load policy. * <!--Global Delayed Loading Policy--> <setting name="lazyLoadingEnabled" value="true"/>

9. Summary

Annotation Development and xml Analysis of Mapping File Configuration 1.For development efficiency: Annotation writing is simpler and more efficient. 2.In terms of maintainability: Notes If you want to modify, you must modify the source code, which will result in increased maintenance costs. xml Mapping profiles are more maintainable. 3.In actual development: two development methods are used in combination. CURD Comments can be used for development; complex queries can be used xml Develop the way configuration files are mapped.

4 October 2021, 12:32 | Views: 6621

Add new comment

For adding a comment, please log in
or create account

0 comments