MongoDB程序开发之ORM工具Morphia

首先介绍抽象类AbstractMongoDAO,里面包含有Morphia的初始化代码,因此继承了BasicDAO。AbstractMongoDAO.java:

Java代码   收藏代码
  1. public class AbstractMongoDAO<T, K> extends BasicDAO<T, K> {  
  2.   
  3.     protected static final Morphia morphia = createMorphia();  
  4.   
  5.     protected static final Mongo mongoInstance = createMongoInstance();  
  6.   
  7.     protected static final Datastore morphiaDs = createDataStore();  
  8.   
  9.     protected AbstractMongoDAO(Class<T> entityClass, Datastore ds) {  
  10.         super(entityClass, ds);  
  11.     }  
  12.   
  13.     private static Morphia createMorphia() {  
  14.         return new Morphia();  
  15.     }  
  16.   
  17.     private static Datastore createDataStore() {  
  18.         morphia.mapPackage("mongodb.orm.model"true);//映射model的包路径  
  19.         if (DatabaseProject.DB_CONFIG.containsKey("mongodb.username")) {  
  20.             return morphia.createDatastore(mongoInstance, DatabaseProject.DB_CONFIG.getString("mongodb.db")  
  21.                     , DatabaseProject.DB_CONFIG.getString("mongodb.username"), DatabaseProject.DB_CONFIG.getString("mongodb.password").toCharArray());  
  22.         }  
  23.         Datastore ds = morphia.createDatastore(mongoInstance, DatabaseProject.DB_CONFIG.getString("mongodb.db"));  
  24.         ds.ensureIndexes();  
  25.         return ds;  
  26.     }  
  27.   
  28.     protected AbstractMongoDAO(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {  
  29.         super(entityClass, mongo, morphia, dbName);  
  30.     }  
  31.   
  32.     private static Mongo createMongoInstance() {  
  33.         MongoOptions mo = new MongoOptions();  
  34.         mo.socketKeepAlive=true;  
  35.         mo.autoConnectRetry = true;  
  36.         mo.maxAutoConnectRetryTime=10;  
  37.         mo.connectionsPerHost = 40;  
  38.         mo.connectTimeout = 20 * 1000;  
  39.         mo.socketTimeout = 60 * 1000;  
  40.         try {  
  41.             if (DatabaseProject.DB_CONFIG.containsKey("mongodb.ips")) {  
  42.                 return new Mongo(getServerAddrsFromConf("mongodb"),mo);  
  43.             }  
  44.             return new Mongo(new ServerAddress(DatabaseProject.DB_CONFIG.getString("mongodb.ip"), DatabaseProject.DB_CONFIG.getInt("mongodb.port")),mo);  
  45.         } catch (Throwable e) {  
  46.             DatabaseProject.LOGGER.error("Failed to init mongodb", e);  
  47.             throw new ExceptionInInitializerError(e);  
  48.         }  
  49.     }  
  50.   
  51.     @SuppressWarnings("unchecked")  
  52.     public static List<ServerAddress> getServerAddrsFromConf(String confKeyPre) throws NumberFormatException, UnknownHostException {  
  53.         ArrayList<ServerAddress> res = new ArrayList<ServerAddress>();  
  54.         List<Object> ips = DatabaseProject.DB_CONFIG.getList(confKeyPre + ".ips");  
  55.         List<Object> ports = DatabaseProject.DB_CONFIG.getList(confKeyPre + ".port");  
  56.         if (ports.size() < ips.size()) {  
  57.             int defPort = 0;  
  58.             if (ports.size() != 0) defPort = Integer.parseInt(ports.get(0).toString());  
  59.             for (int i = 0; i < ips.size(); ++i) {  
  60.                 if (defPort == 0) res.add(new ServerAddress(ips.get(i).toString()));  
  61.                 else res.add(new ServerAddress(ips.get(i).toString(), defPort));  
  62.             }  
  63.         } else {  
  64.             for (int i = 0; i < ips.size(); ++i) {  
  65.                 res.add(new ServerAddress(ips.get(i).toString(),  
  66.                         Integer.parseInt(ports.get(i).toString())));  
  67.             }  
  68.         }  
  69.         return res;  
  70.     }  
  71.   
  72.     public static Mongo getMongoInstance() {  
  73.         return mongoInstance;  
  74.     }  
  75.   
  76.     public static DB getDB() {  
  77.         return morphiaDs.getDB();  
  78.     }  
  79.   
  80.     public static Morphia getMorphia() {  
  81.         return morphia;  
  82.     }  
  83.       
  84.     public Iterable<Key<T>> insert(Iterable<T> entries, WriteConcern wc) {  
  85.         return ds.insert(entries, wc);  
  86.     }  
  87.   
  88.     public Iterable<Key<T>> insert(Iterable<T> entries) {  
  89.         return ds.insert(entries);  
  90.     }    
Java代码   收藏代码
  1. }  

注意createMongoInstance方法(上一篇介绍mongo java driver的文章中也有提到),主要是实例化一个mongo实例。

接下来是createDataStore方法,该方法通过morphia对象及使用mongo实例创建一个Datastore对象。其中morphia.mapPackage("mongodb.orm.model", true);是将mongodb.orm.model包路径下的所有类都进行关系对象映射。

下面是Model类:

Java代码   收藏代码
  1. /** 
  2.  * @Entity 
  3.  * value代表生成的集合名称、不写默认为类名(此处设置为与类名相同) 
  4.  * noClassnameStored如果设置为false,文档中会生成一列className保存类名("className":"mongodb.orm.model.OrmColl") 
  5.  */  
  6. @Entity(value="OrmColl",noClassnameStored = true)  
  7. /** 
  8.  * @Indexes 
  9.  * 创建复合索引(用,分隔). 
  10.  * 此处设置userId升序,name降序. 
  11.  * unique:设置为唯一,无法插入重复值. 
  12.  * dropDups:当为某个字段创建唯一索引时,删除其他相同值的记录。只保留第一条记录. 
  13.  *          true-删除重复,false-不删除重复(当有重复值时唯一索引创建失败),默认为false. 
  14.  * @Indexes({@Index(...),@Index(...)})多个索引加{}并用,分隔. 
  15.  * Datastore的ensureIndexes调用时才会创建索引. 
  16.  */  
  17. @Indexes(@Index(value="userId,-name",unique=true,dropDups=false))  
  18. public class OrmColl{  
  19.     @Id   
  20.     private ObjectId id;//Id  
  21.       
  22.     private long userId;  
  23.     private String name;  
  24.       
  25.     private int age;  
  26.     private Date createDate = new Date();  
  27.     @Property("male")//该属性存储到collection中元素名指定为male  
  28.     private boolean sex;  
  29.       
  30.     /** 
  31.      * concreteClass:为接口指名实现类,默认 
  32.      * java.util.ArrayList for List  
  33.      * java.util.HashSet for Set  
  34.      * java.util.HashMap for Map 
  35.      * 此处为List指明实现类为java.util.Vector 
  36.      */  
  37.     @Property(concreteClass=java.util.Vector.class)  
  38.     public List<String> list;//添加范型指名list类型,否则出现警告  
  39.       
  40.     @Embedded(value="embedded_doc")  
  41.     private InnerDocument doc;//嵌入文档,默认为属性名.此处指定了元素名称.  
  42.       
  43.     @Transient  
  44.     private int transientValue;//设置为@Transient不会被持久化  
  45.     @Serialized  
  46.     private int serializedValue;//序列化  
  47.       
  48.     @Version  
  49.     Long version;//乐观锁  
  50.       
  51.     @Reference  
  52.     private RefOrmColl refOrmColl;//自动生成名为refOrmColl的内嵌文档,包含"$ref"和"$id"属性,指明引用集合名及@Id属性值.  
  53.       
  54.     @Reference  
  55.     private List<RefOrmColl> refList;//自动生成名为refList的数组,数组的每个元素都是内嵌文档,文档形式同refOrmColl.  
  56.       
  57.     public OrmColl(){}  
  58.       
  59.     @PrePersist   
  60.     private void prePersist() {createDate = new Date();}  
  61.   
  62.         //setter & getter  
  63. }  

补充@Entity(concern = "SAFE")属性(粘贴自文档):

NONE: No exceptions are raised, even for network issues

NORMAL: Exceptions are raised for network issues, but not server errors

SAFE: Exceptions are raised for network issues, and server errors; waits on a server for the write operation

FSYNC_SAFE: Exceptions are raised for network issues, and server errors and the write operation waits for the server to flush the data to disk

REPLICAS_SAFE: Exceptions are raised for network issues, and server errors; waits for at least 2 servers for the write operation 

其中version属性不需要getter和setter方法,内嵌对象为InnerDocument。代码如下:

 

Java代码   收藏代码
  1. /** 
  2.  * 被@Embedded注解的类不允许有@Id 
  3.  */  
  4. @Embedded  
  5. public class InnerDocument {  
  6.     private String type;  
  7.     private long longValue;  
  8.     private Date createDate;  
  9.       
  10.     public InnerDocument(){}  
  11.       
  12.     @PrePersist   
  13.     private void prePersist() {createDate = new Date();}  
  14.           
  15.         //setter & getter...  
  16. }  

引用对象为RefOrmColl.java,格式如下:

 

Java代码   收藏代码
  1. @Entity(value="RefOrmColl",noClassnameStored = true)  
  2. public class RefOrmColl {  
  3.     @Id  
  4.     private ObjectId id;//被关联的集合一定要包含@Id属性  
  5.     private long longValue;  
  6.     private String type;  
  7.     private Date date;  
  8.       
  9.     @PrePersist   
  10.     private void prePersist() {date = new Date();}  
  11.         
  12.        //setter&getter...  
  13.   
  14. }  

在OrmColl的集合中自动生成RefOrmColl类型对象属性名的内嵌文档或数组(本例中是refOrmColl和refList),包含"$ref"和"$id"属性,以指明引用集合名及@Id属性值. 

 

DAO实现类:

OrmCollDao.java如下:

 

Java代码   收藏代码
  1. public class OrmCollDao extends AbstractMongoDAO<OrmColl,ObjectId>{//OrmColl主键是OjectId  
  2.       
  3.     private static OrmCollDao childDaoInstance = createDAOInstance();  
  4.       
  5.     protected static DefaultMorphiaMongoDAO<RefOrmColl> refDao = DefaultMorphiaMongoDAO.getInstance(RefOrmColl.class);   
  6.       
  7.     private static OrmCollDao createDAOInstance(){  
  8.         return new OrmCollDao(OrmColl.class,morphiaDs);  
  9.     }  
  10.       
  11.     protected OrmCollDao(Class<OrmColl> entityClass,Datastore ds){  
  12.         super(entityClass,ds);  
  13.     }  
  14.       
  15.     protected OrmCollDao(Class<OrmColl> entityClass, Mongo mongo, Morphia morphia, String dbName){  
  16.         super(entityClass,mongo,morphia,dbName);  
  17.     }  
  18.       
  19.     public static OrmCollDao getInstance(){  
  20.         return childDaoInstance;  
  21.     }  
  22.       
  23.     /** 
  24.      * 数据初始化 
  25.      */  
  26.     public static void insertRefOrmColl(){  
  27.         List list = new ArrayList();  
  28.         for(int i=0;i<100;i++){  
  29.             RefOrmColl roc = new RefOrmColl();  
  30.             roc.setLongValue(i);  
  31.             roc.setType("type"+i);  
  32.             list.add(roc);  
  33.         }  
  34.         //insert可以批量插入list,save只能单个插入,但save可以更新.  
  35.         refDao.insert(list);  
  36.     }  
  37.       
  38.     /** 
  39.      * 数据初始化 
  40.      */  
  41.     public static void insertOrmColl(){  
  42.         //List<OrmColl> ormList = new ArrayList<OrmColl>();  
  43.         //查询一个关联集合的List  
  44.         Query<RefOrmColl> listQuery = refDao.createQuery().field("longValue").lessThan(10);  
  45.         List<RefOrmColl> refList = refDao.find(listQuery).asList();  
  46.         for(int i=0;i<100;i++){  
  47.             OrmColl oc = new OrmColl();  
  48.             oc.setAge(1+i);  
  49.             oc.setName("name"+i);  
  50.             oc.setUserId(10000+i);  
  51.             oc.setSex(true);  
  52.             oc.setTransientValue(12345);  
  53.             oc.setSerializedValue(1234567);  
  54.             InnerDocument doc = new InnerDocument();//内嵌文档  
  55.             doc.setType("type_str");  
  56.             doc.setLongValue(1986L);  
  57.             oc.setDoc(doc);  
  58.             Query<RefOrmColl> query = refDao.createQuery().field("longValue").equal(i);  
  59.             RefOrmColl refColl = refDao.findOne(query);//查询关联集合的文档  
  60.             if(refColl!=null){  
  61.                 //设置关联  
  62.                 oc.setRefOrmColl(refColl);  
  63.                 oc.setRefList(refList);  
  64.             }  
  65.             OrmCollDao.getInstance().save(oc);//使用save方法会自动生成@version属性  
  66.             //ormList.add(oc);  
  67.         }  
  68.         //OrmCollDao.getInstance().insert(ormList);//使用批量插入,文档中不会自动生成@version属性.  
  69.     }  
  70.       
  71.     /** 
  72.      * 根据id加载对象 
  73.      */  
  74.     public static void get(String _id){  
  75.         OrmCollDao dao = OrmCollDao.getInstance();  
  76.         OrmColl obj = dao.get(new ObjectId(_id));  
  77.         displayObj(obj);  
  78.     }  
  79.       
  80.     /** 
  81.      * filter查询方式(直接使用 > < >= <= = exists等表达式) 
  82.      */  
  83.     public static void findByFilter(){  
  84.         OrmCollDao dao = OrmCollDao.getInstance();  
  85.         //filter之间以and连接  
  86.         Query query = dao.createQuery().filter("age >",1);  
  87.         query.filter("userId <="10010);  
  88.         query.filter("male ="true);  
  89.         query.filter("embedded_doc.type =""type_str");  
  90.         query.filter("refList exists "true);  
  91.         List<OrmColl> list = dao.find(query).asList();  
  92.         System.out.println("list.size:"+list.size());  
  93.         for(int i=0;i<list.size();i++){  
  94.             displayObj(list.get(i));  
  95.         }  
  96.     }  
  97.       
  98.     /** 
  99.      * Fluent查询方式(使用morphia封装的方法greaterThan、lessThanOrEq、equal、exists) 
  100.      */  
  101.     public static void findByFluent(){  
  102.         OrmCollDao dao = OrmCollDao.getInstance();  
  103.         Query query = dao.createQuery();  
  104.         //不同条件之间为and  
  105.         query.field("age").greaterThan(1);  
  106.         query.field("userId").lessThanOrEq(10010);  
  107.         query.field("male").equal(true);  
  108.         query.field("embedded_doc.type").equal("type_str");  
  109.         query.field("refList").exists();//doesNotExist  
  110.         List<OrmColl> list = dao.find(query).asList();  
  111.         System.out.println("list.size:"+list.size());  
  112.         for(int i=0;i<list.size();i++){  
  113.             displayObj(list.get(i));  
  114.         }  
  115.     }  
  116.       
  117.     /** 
  118.      * Fluent查询方式(根据id查询文档) 
  119.      */  
  120.     public static void findById(String _id){  
  121.         OrmCollDao dao = OrmCollDao.getInstance();  
  122.         Query query = dao.createQuery();  
  123.         query.field(Mapper.ID_KEY).equal(new ObjectId(_id));//Mapper.ID_KEY == "_id"  
  124.         OrmColl obj = dao.findOne(query);  
  125.         displayObj(obj);  
  126.     }  
  127.       
  128.     /** 
  129.      * Fluent查询方式 ,OR条件查询 
  130.      */  
  131.     public static void orQuery(){  
  132.         OrmCollDao dao = OrmCollDao.getInstance();  
  133.         Query<OrmColl> query = dao.createQuery();  
  134.         query.or(  
  135.             query.criteria("userId").equal(10010),  
  136.             query.criteria("age").greaterThan(1)  
  137.         );  
  138.         List<OrmColl> list = dao.find(query).asList();  
  139.         System.out.println("list.size:"+list.size());  
  140.         for(int i=0;i<list.size();i++){  
  141.             displayObj(list.get(i));  
  142.         }  
  143.     }  
  144.       
  145.     /** 
  146.      * Count求和 
  147.      */  
  148.     public static void getCount(){  
  149.         OrmCollDao dao = OrmCollDao.getInstance();  
  150.         Query query = dao.createQuery().field("userId").greaterThanOrEq(10095);  
  151.         long count = dao.count(query);  
  152.         System.out.println(count);  
  153.     }  
  154.       
  155.     /** 
  156.      * 更新操作 
  157.      */  
  158.     public static void updateEntity(String _id){  
  159.         OrmCollDao dao = OrmCollDao.getInstance();  
  160.         UpdateOperations<OrmColl> ops = dao.createUpdateOperations().set("createDate",new Date()).set("serializedValue",12345);  
  161.         UpdateResults<OrmColl> ur = dao.update(dao.createQuery().field(Mapper.ID_KEY).equal(new ObjectId(_id)),ops);  
  162.         System.out.println(ur.getInsertedCount());  
  163.     }  
  164.       
  165.     /** 
  166.      * 对象转换并打印对象属性 
  167.      */  
  168.     public static void displayObj(OrmColl obj){  
  169.         Morphia morphia = getMorphia();  
  170.         DBObject object = morphia.toDBObject(obj);//将对象转换成DBObject.  
  171.         System.out.println(object.toString());  
  172.     }  
  173.       
  174.     /** 
  175.      * Mapper and EntityCache 
  176.      */  
  177.     public static void mapper(String _id){  
  178.         OrmCollDao dao = OrmCollDao.getInstance();  
  179.         OrmColl oc = dao.get(new ObjectId(_id));  
  180.           
  181.         Mapper mapper = morphia.getMapper();  
  182.           
  183.         if(mapper!=null && morphia.isMapped(OrmColl.class)){  
  184.             System.out.println("getCollectionName:"+mapper.getCollectionName(oc));  
  185.             System.out.println("Id:"+mapper.getId(oc));  
  186.             System.out.println("Key:"+mapper.getKey(oc));  
  187.             System.out.println("keyToRef:"+mapper.keyToRef(mapper.getKey(oc)));  
  188.             System.out.println("Options:"+mapper.getOptions());  
  189.         }  
  190.           
  191.         EntityCache cache = mapper.createEntityCache();  
  192.         cache.putEntity(mapper.getKey(oc),oc);  
  193.           
  194.         System.out.println("cache obj 1: "+cache.getEntity(mapper.getKey(oc)).getName());  
  195.         System.out.println("cache obj 2: "+cache.getEntity(mapper.getKey(oc)).getName());  
  196.         System.out.println("cache obj exists: "+cache.exists(mapper.getKey(oc)));  
  197.           
  198.         EntityCacheStatistics ecs = cache.stats();  
  199.         System.out.println("EntityCacheStatistics1: "+ecs.toString());//cache统计1: 1 entities,3 hits  
  200.           
  201.         cache.putProxy(mapper.getKey(oc),oc);  
  202.         System.out.println("cache proxy: "+cache.getProxy(mapper.getKey(oc)).getName());  
  203.           
  204.         ecs = cache.stats();  
  205.         System.out.println("EntityCacheStatistics2: "+ecs.toString());//cache统计2: 2 entities,4 hits  
  206.           
  207.         //所有已经映射的class  
  208.         for (MappedClass mc : mapper.getMappedClasses()) {  
  209.             System.out.println("getMappedClasses: " + mc);  
  210.         }  
  211.         for (EntityInterceptor ei : mapper.getInterceptors()) {  
  212.             System.out.println("EntityInterceptor: " + ei);  
  213.         }  
  214.           
  215.     }  
  216. }  

以上是针对OrmColl的集合建立的DAO,由于使用了泛型,因此find、update等操作都针对OrmColl,所以如果你需要在DAO中同时对其它集合进行操作的话,可以使用以下通用的DAO,DefaultMorphiaMongoDAO.java:

 

Java代码   收藏代码
  1. public class DefaultMorphiaMongoDAO<T> extends AbstractMongoDAO<T, ObjectId> {  
  2.     private static final Map<String,DefaultMorphiaMongoDAO> _instanceMap = new ConcurrentHashMap<String,DefaultMorphiaMongoDAO>();  
  3.       
  4.     protected DefaultMorphiaMongoDAO(Class<T> entityClass, Datastore ds) {  
  5.         super(entityClass,ds);  
  6.         this.ensureIndexes();  
  7.     }  
  8.       
  9.     public static DB getDB(){  
  10.         return morphiaDs.getDB();  
  11.     }  
  12.       
  13.     public static <T> DefaultMorphiaMongoDAO<T> getInstance(Class<T> clazz){  
  14.         DefaultMorphiaMongoDAO inst = _instanceMap.get(clazz.getSimpleName());  
  15.         if (inst==null) {  
  16.             inst = new DefaultMorphiaMongoDAO<T>(clazz,morphiaDs);  
  17.             _instanceMap.put(clazz.getSimpleName(),inst);  
  18.         }  
  19.         return inst;  
  20.     }  
  21.   
  22. }  

 通过泛型,你就可以用该DAO对任何Collection进行操作了,(注意,此处代码,<T, ObjectId>可以支持不同的Key类型,不一定是ObjectId)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值