`
truemylife
  • 浏览: 230030 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论
阅读更多

       morphia是mongodb for java基础上的一个开源项目,但2011年之后几乎不在更新,非常不活跃,建议后来者谨慎选择。由于团队在比较早之前就选择了morphia,因此在未重构之前,还是尽可能的用好morphia。

morphia项目地址:

https://code.google.com/p/morphia/

这里只说morphia Reference使用的问题和使用建议

一、慎用Reference,合理使用lazy=true

@Reference有lazy属性,默认为false,当为false时,会自动加载关联的数据,跟hibernate类似。理论上Reference会引发死循环,最简单的业务模式,就是好友业务,用户A通过Reference加载关联的好友B,B通过Reference加载关联的好友A,就形成了死循环。因此在确定类似这样的业务或者业务复杂到开发人员不能掌控时,非常有必要把lazy=true。如果形成死循环,会造成链接池耗尽,请求被阻塞,占用较多的cpu,整个应用变的极慢。因此强列建议慎用@Reference,如果要用,一定要搞清楚业务,在没必要实时加载引用数据的情况下,务必加上lazy=true。

 

二、第三方依赖

@Reference(lazy=true)

设置lazy=true后,会发现需要cglib及proxytoys第三方包的支持,需要加入对应的jar包。

 

三、多个mongodb数据库,且采用spring配置时引出的Reference bug及解决办法

如果mongodb两个database,spring配置片段如下:

 

  

<bean id="mongouri" class="com.mongodb.MongoURI">
	 <constructor-arg value="${mongo.url}"/>
</bean>
<bean id="mongo" class="com.mongodb.Mongo">
	<constructor-arg><ref bean="mongouri"></ref></constructor-arg>
</bean>
<bean id="morphia" class="com.google.code.morphia.Morphia">
       <property name="mongo" ref="mongo"/>
       <property name="databaseName" value="cmac"/>
       <property name="user" value="${mongo.username}"/>
       <property name="password" value="${mongo.password}"/>
</bean>
<bean id="practisemorphia" class="com.google.code.morphia.Morphia">
	<property name="mongo" ref="mongo"/>
        <property name="databaseName" value="practise"/>
        <property name="user" value="${mongo.username}"/>
        <property name="password" value="${mongo.password}"/>
</bean>
<bean id="datastore" factory-bean="morphia" factory-method="getDatastore"/>
<bean id="practiseds" factory-bean="practisemorphia" factory-method="getDatastore"/>

 

       我们为两个database分别写了两个BaseDao,让两个BaseDao分别持有不同的DatastoreImpl,没有问题,但是在使用Reference且lazy=true时,问题来了。如上的配置,spring初始化时先初始化datastore,再初始化practiseds,应用起来后,发现practiseds相关的@Reference(lazy=true)操作都正常,而datastore相关的@Reference(lazy=true)不正常,报的错误是MappingException。通过查看源码,发现getDatastore调用DatastoreHolder时是静态且单例的模式,因此当初始化practiseds时,就把之前的DatastoreHolder的静态变量覆盖了。Reference在lazy=true的情况下,会从DatastoreHolder里取当前的DatatoreImpl,而此时取到的都只是practiseds的DatatoreImpl,因此datastore相关的@Reference(lazy=true)通通抛出MappingException异常。

此问题的修复,只要在Dao对应方法里,加上以下代码:

DatastoreHolder.getInstance().set(super.getDs());

 //在BaseDao里定义DatastoreImpl成员变量并注入@Resource(name = "datastore")

 

public DatastoreImpl getDs() {
		return ds;
	}

	@Resource(name = "datastore")
	public void setDs(DatastoreImpl ds) {
		this.ds = (DatastoreImpl)ds;
		initType(((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]));
		ensureIndexes();
	}

 

为了书写更加美观和便利,可以改造成AOP的方式

 

SupportReference.java

 

 

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SupportReference {}

 

 

AbstractMorphiaReferenceAspect.aj

 

 

public abstract aspect AbstractMorphiaReferenceAspect {

	public AbstractMorphiaReferenceAspect() {
	}
	
	@SuppressAjWarnings("adviceDidNotMatch")
	Object around(Object model) : supportReferenceMethodExecution(model) {
		@SuppressWarnings("rawtypes")
		Class clazz = model.getClass().getSuperclass();
		try{
		@SuppressWarnings("unchecked")
		Method ds = clazz.getDeclaredMethod("getDs");
		DatastoreImpl datastoreimpl =(DatastoreImpl)ds.invoke(model);
		DatastoreHolder.getInstance().set(datastoreimpl);
		}catch(Exception ex){ex.printStackTrace();}
		Object result = proceed(model);
		return result;
	}
	
	
	protected abstract pointcut supportReferenceMethodExecution(Object model);
}

 

 

MorphiaReferenceAspect.aj

 

 

public aspect MorphiaReferenceAspect extends AbstractMorphiaReferenceAspect {
	public MorphiaReferenceAspect() {
		super();
	}

	protected pointcut supportReferenceMethodExecution(Object model) : 
		(execution(* com.hx.corebiz.*.dao.impl.*.*(..))) && 
				@annotation(SupportReference) &&
				this(model);
	
}

 

 

 aop.xml

 

<?xml version="1.0" encoding="UTF-8" ?>
<aspectj>
	<aspects>
	<aspect name="com.hx.corebase.aop.morphiareference.MorphiaReferenceAspect" /> 
	</aspects>
	<weaver options="-verbose">
		<include within="com.hx.corebiz.*.dao.impl.*" />
        </weaver>
</aspectj>

 

在Dao类里,在需要使用@Reference(lazy=true)方法的加上Annotation @SupportReference即可

 

 四、ignoreMisssing

ignoreMisssing会捕获Reference所有异常,如果不想看到一些烦人的异常,并让程序继续运行,ignoreMisssing=true是有必要的。比方说我们Reference到另一张表,某天另一张表的数据删除了,而开发人员也没有做关联数据的清理,此时如果ignoreMisssing=false(默认),就会抛出异常,这种情况下有必要指定ignoreMisssing=true。

 

五、Memcached与Reference

存入Memcached时,会对对象进行序列化,此时应注意以下三点:

1、如果你不想序列化对象里某成员,请使用transient关键字,这样可减小对象大小,节省内存空间,提高性能。

2、如果lazy=false,在序列化存入到memcache时,会加载出所有Reference对象。如果Reference是个大List<Object>,可以想像此java对象将会非常庞大。而memcache更适合小对象的缓存,默认在1M之内。不过这个策略跟总大小也有关系,本人设置memcached内存总大小为64M,放入一个大对象,报错信息page超过1M,但把总大小置成512M后,与之前一样没有设置PAGE大小(即参数-L),这时就不报错了,没有仔细研究memcache代码,但据此可判断此1M的限制,跟总大小有某种逻辑关系。当然如果光光为了消除1M限制的错误,可以通过设置-L,比如设置成5M,但这不是理想的解决办法。通过测试,memcached对一个大对象和一个小对象的存取,速度不在一个数量级上,因此如果真的有对象超过1M,最好对程序进行优化设计。像上述的情况Reference是个大List<Object>,此时把lazy=true,是非常有必要的。可大大减小对象的大小。

3、另外重复第一点,在互相引用的时候,此时如不加lazy=true,就会产生死循环,因此这种情况下lazy=true是必须的。

分享到:
评论

相关推荐

    使用Morphia框架操作mongodb

    本文将深入探讨如何使用Morphia框架来操作MongoDB。 首先,你需要在项目中添加Morphia和MongoDB驱动的依赖。如果你使用的是Maven,可以在pom.xml文件中加入以下依赖: ```xml &lt;groupId&gt;org.mongodb.morphia ...

    morphia-reference-example:该教程的源代码可从http:__www.microsoft.com_en_us_

    在这个教程中,开发者可以学习到如何在Morphia的数据实体类中使用`@Reference`注解。这个注解的目的是将一个对象的ID存储为另一个对象的属性,从而建立了一种引用关系,而不是直接保存整个对象。这样做的好处包括...

    Morphia使用问题及解决方案集锦

    在使用Morphia框架时,经常会遇到需要更新具有`@Reference`注解的集合字段的情况。例如,在更新`UserGroup`中的成员列表时可能会遇到问题。 ##### 1.1 User类定义 ```java @Entity("User") public class User { @...

    morphia所用到的jar包

    在这个压缩文件中,我们有两个重要的jar包:mongo-2.7.3.jar和morphia-0.99.jar,它们都是针对Morphia框架使用的。 MongoDB的Java驱动程序,即mongo-2.7.3.jar,是连接Java应用程序与MongoDB服务器的关键组件。它...

    使用 Morphia 和 MongoDB 实现域模型持久性(ZZ)

    本篇文章将详细介绍如何使用 Morphia 和 MongoDB 来实现域模型的持久化。 首先,我们需要理解 Morphia 的基本概念。Morphia 将 Java 对象映射到 MongoDB 的文档结构,这包括实体类、数据存储、数据映射和查询API。...

    morphia-0.99.jar

    morphia-0.99.jar 最新版本。

    Mongo的ORM框架的学习Morphia

    在本文中,我们将探讨MongoDB的ORM框架Morphia,并结合Spring Data MongoDB的使用来创建一个集成应用。ORM(对象关系映射)框架是将数据库操作转化为对象模型的方法,简化了开发过程,使得开发者可以专注于业务逻辑...

    morphia.jar和mongo.jar

    使用Morphia时,首先需要配置MongoDB的连接信息,然后定义实体类,这些类通常会继承自Morphia提供的`@Entity`注解的类。接着,可以使用Morphia的`Datastore`接口来执行数据库操作,如保存、查询、更新或删除数据。...

    Morphia和MongoDB学习总结<三>

    通过使用Morphia,开发者可以避免直接处理JSON格式的文档,而是专注于处理Java对象。这使得代码更易于理解和维护。 **二、Morphia的核心概念** 1. **实体(Entities)**:在Morphia中,Java类被视为实体,每个实体...

    spring MVC morphia mongo 整合的例子

    Spring MVC、Morphia 和 MongoDB 是三个在Java开发中常用于构建Web...通过深入研究这个例子,你将能理解如何在实际项目中结合使用Spring MVC、Morphia和MongoDB,从而更好地掌握Java Web开发中的非关系型数据库集成。

    morphia基于mongodb的基本开发

    morphia基于mongodb的基本开发

    morphia-1.3.2.jar

    morphia-1.3.2.jar

    Morphia一个nosql的ORM框架

    在NoSQL的世界里,Morphia扮演着连接应用程序和非关系型数据库的角色,提供了类型安全和易于使用的API。 **一、MongoDB与Morphia** MongoDB是一个流行的文档型数据库,以其灵活性、高性能和横向扩展能力而受到青睐...

    Morphia开发简介.pdf

    - **@Reference**:表示对象是另一个集合文档的引用,Morphia会处理引用关系。 - **@Indexed**:用于为属性创建索引。 - **@Property**:为属性指定MongoDB中的别名。 - **@Transient**:标记字段不应被持久化到...

    Morphia 操作 MongoDB.docx

    要在Java项目中使用Morphia,首先需要下载MongoDB的Java驱动包,可以从GitHub官方仓库下载最新版本。同时,还需要下载Morphia的jar包,通常可以在Google Code仓库中找到。将这两个jar包导入到你的Java项目中,确保...

    Morphia 操作 MongoDB.pdf

    在本文中,我们将深入探讨如何使用 Morphia 进行 MongoDB 的操作。 首先,为了在 Java 项目中使用 Morphia,我们需要下载并引入相关的依赖库。这包括 MongoDB 的 Java 驱动包和 Morphia 的 JAR 文件。可以从官方...

    morphia-1.00-SNAPSHOT.jar

    morphia mongo db OR-mapping mongo db再带的CRUD 太麻烦了, 一个不错的框架 类似 Hibernate

    morphia-example-1:Java中使用Morphia ODM和Spring的示例项目

    "Morphia-example-1:Java中使用Morphia ODM和Spring的示例项目" 是一个基于Java开发的项目,其主要目的是展示如何在Java应用程序中使用Morphia对象数据映射(ODM)库来操作MongoDB数据库,并结合Spring框架进行集成...

Global site tag (gtag.js) - Google Analytics