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

时间:2014-06-03 11:20:13

标签: 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
}

User.java

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

// getters and setters
}

湾数据库架构:

反馈表

                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      | 

用户表:

                Table "public.users"

Column   | Type     |     Modifiers                      
-------------+----------+----------------------------------------------------
id          | integer  | PRIMARY KEY
email       | text     | 

℃。通过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);

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);

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

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

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

我最近的观察:

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

  1. lazyLoadingEnabled:默认值= TRUE

  2. aggressiveLazyLoading:默认值= TRUE

    但是看看他们的源代码:

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

    **但是,如果要更正,结果不会受到影响,延迟加载也无法正常工作:( **

3 个答案:

答案 0 :(得分: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" }));
    }
    
    • 我已将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);
      
    • 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);
      

- 调用映射器的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);
  • 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}

  • 虽然这样做效果令人满意,但在做

configuration.getLazyLoadTriggerMethods().clear();

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

答案 1 :(得分:4)

<强>更新

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

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

protected boolean lazyLoadingEnabled = false;

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

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


老答案:

文档不正确。当aggressiveLazyLoading为true时,在对象上的任何方法调用之后加载所有惰性属性。 因此,调用feedback.toString()将获取反馈的发件人属性。

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

答案 2 :(得分:0)

我认为使用print来验证mybatis中的延迟加载并不容易。 我们可以使用configuration.getLazyLoadTriggerMethods().clear();删除默认的triggerMethods作为上一个答案。但是当我们打印它或使用toString时,它仍然会调用getXXX。因此它仍然会触发延迟加载以选择更多内容。因此,我们无法调试或打印以查看延迟加载的过程。

我找到了一种验证此功能的方法。

  1. 设置日志级别以进行调试。
  2. 编写以下代码,然后查看控制台。
        log.info("user :{}", userLazyDepartment);
        log.info("user :{}", userLazyDepartment.getDepartment());