使用MyBatis 3和Java进行延迟加载

hem*_*vsn 8 java sql mybatis

我使用Mybatis(3.2.7版本)作为我的JAVA项目的ORM框架.由于我来自JPA背景,我很想探索Mybatis支持的LAZYLOADING.但我无法透露任何实质性内容.
(我正在使用JAVA API和注释配置MYBATIS仅用于查询目的)

根据Mybatis文档: 1.lazyLoadingEnabled:默认值= TRUE

全局启用或禁用延迟加载.启用后,所有关系都将被延迟加载.通过在其上使用fetchType属性,可以为特定关系取代此值.

2. aggressiveLazyLoading:默认值= TRUE

启用后,将在调用任何延迟属性时完全加载具有延迟加载属性的对象.否则,每个属性都按需加载.

使用以下属性,我尝试了以下代码:

一个.JAVA课程:

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
}
Run Code Online (Sandbox Code Playgroud)

User.java

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

// getters and setters
}
Run Code Online (Sandbox Code Playgroud)

湾 数据库架构:

反馈表

                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      | 
Run Code Online (Sandbox Code Playgroud)

用户表:

                Table "public.users"

Column   | Type     |     Modifiers                      
-------------+----------+----------------------------------------------------
id          | integer  | PRIMARY KEY
email       | text     | 
Run Code Online (Sandbox Code Playgroud)

C.通过JAVA API配置MyBatis:

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);
Run Code Online (Sandbox Code Playgroud)

d.在Feedbackmapper中查询DB和DB查询:

d.1 Feedbackmapper中的代码:

@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);
Run Code Online (Sandbox Code Playgroud)

d.2:在feedbackMapper中调用查询的代码

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

但是在查询getFeedback(id)时仍会填充"sender"对象.我希望不应该立即填充发送方对象,但只有当我在获取的反馈对象上调用getSender()时才会填充.请帮忙.

我最近的观察:

Mybatis团队确实在他们的文档中出错,即在文档中:

  1. lazyLoadingEnabled:默认值= TRUE

  2. aggressiveLazyLoading:默认值= TRUE

    但看看他们的源代码:

     protected boolean lazyLoadingEnabled = false;
     protected boolean aggressiveLazyLoading = true;
    
    Run Code Online (Sandbox Code Playgroud)

    **但是,正在纠正,结果不受影响,延迟加载不起作用:(**

hem*_*vsn 7

我想我找到了一种启用延迟加载的方法(尽管不是百分之百确定):

  • MyBatis文档在配置中有以下设置:

设置:lazyLoadTriggerMethods

描述:指定哪个Object的方法触发延迟加载

有效值:以逗号分隔的方法名称列表

默认值:equals,clone,hashCode,toString

  • 根据源代码,这个东西正确映射到文档中给出的内容:

    public class Configuration {
    // other attributes + methods
    protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new         
    String[] { "equals", "clone", "hashCode", "toString" }));
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • 我已将Mybatis配置更改为:

      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);
      
      Run Code Online (Sandbox Code Playgroud)
    • Mapper中的查询(大部分未更改):

      @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);
      
      Run Code Online (Sandbox Code Playgroud)

- 调用映射器的JAVA代码

        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);
Run Code Online (Sandbox Code Playgroud)
  • 输出CODE

1.发送者懒惰加载前的反馈对象:

{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}
Run Code Online (Sandbox Code Playgroud)

  • 虽然这可以令人满意地工作

configuration.getLazyLoadTriggerMethods().clear();

然而,由于缺乏Mybatis的文档,我不确定,这是否与任何缺点有关.


Chr*_*ras 4

更新

我查看了源代码,问题是 Configuration 类没有反映文档。

在配置类中,默认情况下禁用延迟加载。这在提交f8ddba364092d819f100e0e8f7dec677c777d588中发生了变化,但文档未更新以反映更改。

protected boolean lazyLoadingEnabled = false;
Run Code Online (Sandbox Code Playgroud)

我填写了错误报告https://github.com/mybatis/mybatis-3/issues/214

现在,添加configuration.setLazyLoadingEnabled(true)以启用延迟加载。


旧答案:

该文档不正确。当aggressiveLazyLoading 为true 时,所有惰性属性都会在对象上的任何方法调用后加载。因此调用 Feedback.toString() 将获取 Feedback 的 sender 属性。

您应该将aggressiveLazyLoading 设置为 false 才能实现您想要的效果。