MongoDB Java Driver 源码分析(5):com.mongodb.DB
程序员文章站
2022-03-02 16:17:25
...
DB 表示数据库连接,是一个抽象类,部分核心功能由子类提供,由 DBApiLayer 继承。
由子类实现的抽象方法
// 开始数据库连接 public abstract void requestStart(); // 结束数据库连接 public abstract void requestDone(); // 保持数据库连接 public abstract void requestEnsureConnection(); // 获取指定名称的数据集 protected abstract DBCollection doGetCollection( String name );
数据集相关的方法
// 创建数据集 public final DBCollection createCollection( String name, DBObject options ){ // 如果 options 不为空 // 则先以 options 构造创建数据库的命令 // 然后执行创建数据库的命令并得到结果 if ( options != null ){ DBObject createCmd = new BasicDBObject("create", name); createCmd.putAll(options); CommandResult result = command(createCmd); result.throwOnError(); } return getCollection(name); } // 解析用 "." 分隔的字符串,获取指定的数据集 public DBCollection getCollectionFromString( String s ){ DBCollection foo = null; // 获取 "." 所在位置 int idx = s.indexOf( "." ); // 当分解后的字符串中仍然包含 "." 时 // 循环分解字符串,知道所有 "." 号解析完毕 // 效果类似于递归调用,但这里采用了循环的写法 while ( idx >= 0 ){ // 获取 "." 之前的字符串 b String b = s.substring( 0 , idx ); // 获取 "." 之后的字符串 s s = s.substring( idx + 1 ); // 检查上次解析得到的对象 foo 是否为空 if ( foo == null ) foo = getCollection( b ); else foo = foo.getCollection( b ); // 获取 "." 所在位置 idx = s.indexOf( "." ); } if ( foo != null ) return foo.getCollection( s ); return getCollection( s ); } // 获取所有数据集名称 public Set<String> getCollectionNames() throws MongoException { // 获取系统的 namespace 数据集 DBCollection namespaces = getCollection("system.namespaces"); if (namespaces == null) throw new RuntimeException("this is impossible"); // 获取用于遍历 namespace 的迭代器 Iterator<DBObject> i = namespaces.__find(new BasicDBObject(), null, 0, 0, 0, getOptions()); if (i == null) return new HashSet<String>(); // 表名称 List,最后转换为 set 并返回 List<String> tables = new ArrayList<String>(); for (; i.hasNext();) { DBObject o = i.next(); if ( o.get( "name" ) == null ){ throw new MongoException( "how is name null : " + o ); } // 获取 namespace 名称 String n = o.get("name").toString(); // 获取 namespace 名称前缀 int idx = n.indexOf("."); String root = n.substring(0, idx); // 如果前缀不为当前 DB 的名称 // 表示这个 namespace 不属于当前 DB if (!root.equals(_name)) continue; // 忽略特殊数据集 if (n.indexOf("$") >= 0) continue; // 获取数据集名称 String table = n.substring(idx + 1); tables.add(table); } Collections.sort(tables); // 转换为 Set return new LinkedHashSet<String>(tables); }
数据库命令相关的方法
// 执行数据库命令 public CommandResult command( DBObject cmd , int options ) throws MongoException { // 调用 DBCollection 的 find 方法 Iterator<DBObject> i = getCollection("$cmd").__find(cmd, new BasicDBObject(), 0, -1, 0, options); if ( i == null || ! i.hasNext() ) return null; // 获得数据库命令的返回结果结果 CommandResult res = (CommandResult)i.next(); res._cmd = cmd; return res; } // 以 "eval" 方式解析命令 public CommandResult doEval( String code , Object ... args ) throws MongoException { // 构造 "eval" 命令 // 调用 command 方法执行并获得结果 return command( BasicDBObjectBuilder.start() .add( "$eval" , code ) .add( "args" , args ) .get() ); } // 删除数据库 public void dropDatabase() throws MongoException { CommandResult res = command(new BasicDBObject("dropDatabase", 1)); res.throwOnError(); _mongo._dbs.remove(this.getName()); }
用户相关的方法
// 验证用户名和密码 public CommandResult authenticateCommand(String username, char[] passwd ) throws MongoException { if ( username == null || passwd == null ) throw new NullPointerException( "username can't be null" ); if ( _username != null ) throw new IllegalStateException( "can't call authenticate twice on the same DBObject" ); // 根据用户名和密码,通过 MD5 计算哈希值 String hash = _hash( username , passwd ); // 验证用户名和密码并获得返回结果 CommandResult res = _doauth( username , hash.getBytes() ); res.throwOnError(); _username = username; _authhash = hash.getBytes(); return res; } // 验证用户名和密码并获得返回结果 private CommandResult _doauth( String username , byte[] hash ){ // 获取 "盐值",用于加密 CommandResult res = command(new BasicDBObject("getnonce", 1), getOptions()); res.throwOnError(); // 利用当前的用户名和密码,执行一个没有实际意义的操作 // 利用 username, 加密后的密码,以及盐值进行验证,看看是否产生错误 DBObject cmd = _authCommand( res.getString( "nonce" ) , username , hash ); return command(cmd, getOptions()); } // 利用 username, 加密后的密码,以及盐值进行验证,看看是否产生错误 static DBObject _authCommand( String nonce , String username , byte[] hash ){ // 获取由 username, 加密后的密码,以及盐值 组成的 key String key = nonce + username + new String( hash ); // 构造用于验证用户的命令 BasicDBObject cmd = new BasicDBObject(); cmd.put("authenticate", 1); cmd.put("user", username); cmd.put("nonce", nonce); // 对 key 进行 MD5 加密 cmd.put("key", Util.hexMD5(key.getBytes())); return cmd; } // 添加用户 public WriteResult addUser( String username , char[] passwd, boolean readOnly ){ // 获取系统用户 DBCollection c = getCollection( "system.users" ); // 根据指定的 username 获取用户 DBObject o = c.findOne( new BasicDBObject( "user" , username ) ); // 如果不存在,则创建 if ( o == null ) o = new BasicDBObject( "user" , username ); // 设置密码 o.put( "pwd" , _hash( username , passwd ) ); // 设置只读权限 o.put( "readOnly" , readOnly ); // 将构造出来的用户对象添加到 系统用户数据集 中 return c.save( o ); } // 删除用户 public WriteResult removeUser( String username ){ DBCollection c = getCollection( "system.users" ); return c.remove(new BasicDBObject( "user" , username )); }
推荐阅读
-
MongoDB Java Driver 源码分析
-
MongoDB Java Driver 源码分析(9):com.mongodb.DBport
-
MongoDB Java Driver 源码分析(11):GridFS 类
-
MongoDB Java Driver 源码分析(13):OutputBuffer,BasicOutputBuffer 和 PoolOutputBuffer
-
MongoDB Java Driver 源码分析(1):Package 概述
-
MongoDB Java Driver 源码分析(12):GridFSFile、GridFSDBFile 和 GridFSInputFile
-
MongoDB Java Driver 源码分析(5):com.mongodb.DB
-
MongoDB Java Driver 源码分析(8):com.mongodb.RelicaSetStatus
-
MongoDB Java Driver 源码分析(7):com.mongodb.DBAPILayer
-
MongoDB Java Driver 源码分析(10):com.mongodb 总结