Lazy Download Using MyBatis 3 with Java

I am using Mybatis (version 3.2.7) as the ORM framework for my JAVA project. Since I am against the backdrop of the JPA, I really wanted to learn LAZYLOADING, supported by Mybatis. But I could not understand anything significant.
(I configure MYBATIS using the JAVA API and annotations are for query only)

According to Mybatis documentation: <i> <b> 1. lazyLoadingEnabled: default = TRUE

Globally enables or disables lazy loading. When enabled, all relationships will be lazy loaded. This value can be replaced for a specific relationship using the fetchType attribute on it.

2. aggressive LazyLoading: default = TRUE

When enabled, an object with lazy loaded properties will be fully loaded when you call any of the lazy properties. Otherwise, each property is loaded on demand.

Using the following attributes, I tried the following code:

a. JAVA Classes:

Feedback.java

public class Feedback implements Serializable { private static final long serialVersionUID = 1L; private int id; private String message; /** * while loading Feedback, I want sender object to be lazily loaded */ private User sender; private boolean seen; // getters and setters } 

User.java

 public class User implements Serializable, { private static final long serialVersionUID = 1L; private int id; private String email; // getters and setters } 

b. DB schema:

Review table

  Table "public.feedback" Column | Type | Modifiers -------------+-----------+------------------------------------------------------- id | integer | PRIMARY KEY seen | boolean | not null sender_id | integer | FOREIGN KEY (sender_id) REFERENCES users(id) message | text | 

User table:

  Table "public.users" Column | Type | Modifiers -------------+----------+---------------------------------------------------- id | integer | PRIMARY KEY email | text | 

with. Configuring MyBatis via the JAVA API:

 DataSource dataSource = new PGSimpleDataSource(); ((PGSimpleDataSource) dataSource).setServerName("localhost"); ((PGSimpleDataSource) dataSource).setDatabaseName(dbName); ((PGSimpleDataSource) dataSource).setPortNumber(5432); ((PGSimpleDataSource) dataSource).setUser(new UnixSystem().getUsername()); ((PGSimpleDataSource) dataSource).setPassword(""); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment(dbName, transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(FeedbackMapper.class); // configuration.setAggressiveLazyLoading(false); sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); 

D. Querying DB and DB queries in the Feedbackmapper file:

d.1 Code in reverse order:

 @Select("SELECT f.id, f.message, f.seen, f.sender_id FROM feedback f WHERE f.id= #{feedbackId}") @Results(value = { @Result(property = "id", column = "id"), @Result(property = "sender", column = "sender_id", javaType = User.class, one = @One(select = "getUser", fetchType=FetchType.DEFAULT)) }) public Feedback getFeedback(@Param("feedbackId") int feedbackId); @Select("SELECT id, email FROM users WHERE id=#{id}") public User getUser(int id); 

d.2: Code for calling requests in feedbackMapper

  // setup Mybatis session factory and config Feedback feedback =feedbackMapper.getFeedback(70000); System.out.println(feedback); 

But still, the sender object is populated with a getFeedback (id) request. I expect that the sender object should not be filled immediately, but only when I call getSender () on the selected feedback object. Please help .

My recent observations:

The Mybatis team was really mistaken in its documentation, that is, in the documentation:

  • lazyLoadingEnabled: default = TRUE

  • aggressive LazyLoading: default = TRUE

    But looking at their source code:

      protected boolean lazyLoadingEnabled = false; protected boolean aggressiveLazyLoading = true; 

    ** However, this is a fix, the results are not affected, and lazy loading does not work :( **

+6
source share
2 answers

I think I found a way to enable lazyloading (although not sure about the percentage):

  • The MyBatis documentation has the following configuration settings:

Setup: lazyLoadTriggerMethods

Description: Indicates which method methods trigger lazy loading.

Valid Values: Comma Separated Method Name List

Default: equals, clone, hashCode, toString

  • According to the source code, this thing correctly corresponds to what is given in the documentation:

     public class Configuration { // other attributes + methods protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" })); } 
    • I changed the configuration of Mybatis as follows:

       TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment(dbName, transactionFactory, dataSource); Configuration configuration = new Configuration(environment); /** *This is the cause why LAZY LOADING is working now */ configuration.getLazyLoadTriggerMethods().clear(); /////////////////////////////////////////////////// configuration.setLazyLoadingEnabled(true); configuration.setAggressiveLazyLoading(false); 
    • Requests in Mapper (mostly unchanged) :

       @Select("SELECT id, message, seen, sender_id FROM feedback WHERE f.id= #{feedbackId}") @Results(value = { @Result(property = "id", column = "id"), @Result(property = "sender", column = "sender_id", javaType = User.class, one = @One(select = "getUser")) // Set fetchType as DEFAULT or LAZY or don't set at all-- lazy loading takes place // Set fetchType as EAGER --sender Object is loaded immediately }) public Feedback getFeedback(@Param("feedbackId") int feedbackId); @Select("SELECT id, email FROM users WHERE id=#{id}") public User getUser(int id); 

- JAVA code to call mapper

  FeedbackMapper mapper = sqlSession.getMapper(FeedbackMapper.class); Feedback feedback =mapper.getFeedback(69999); System.out.println("1. Feedback object before sender lazily load: \n"+ feedback); System.out.println("2. Sender loaded explicitly \n" +feedback.getSender()); System.out.println("3. Feedback object after sender loading \n" + feedback); 
  • CODE Output

<i> 1. The feedback object before the sender downloads:

 {id : 69999, message : message123, sender : null, seen : false} 2. Sender loaded explicitly {id : 65538 , email: hemant@gmail.com } 3. Feedback object after sender loading: {id : 69999, message : message123, sender : {id : 65538, email : hemant@gmail.com }, seen : false} 

  • Although this works satisfactorily, doing

configuration.getLazyLoadTriggerMethods().clear();

However, due to the lack of documentation in Mybatis, I am not sure if this is due to any flaws as such.

+6
source

UPDATE

I looked at the source code, and the problem is that the Configuration class does not reflect the document.

In the configuration class, lazy loading is disabled by default. This has changed in commit f8ddba364092d819f100e0e8f7dec677c777d588 , but the document has not been updated to reflect this change.

 protected boolean lazyLoadingEnabled = false; 

I filled out the error report https://github.com/mybatis/mybatis-3/issues/214 .

Now add the configuration.setLazyLoadingEnabled (true) parameter to enable lazy loading.


Old answer:

The documentation is incorrect. When LazyLoading's aggressiveness is true, all lazy properties are loaded after calling any method on the object. Therefore, calling the feedback.toString () function will display the feedback sender property.

You must set the aggressive LazyLoading to false in order to achieve what you want.

+3
source

Source: https://habr.com/ru/post/970235/


All Articles