hibernate--一级和二级缓存(使用Ehcache)以及查询缓存
https://blog.csdn.net/u012411414/article/details/50483185
有一下几点需要理清才行:
一级缓存是session缓存 session关闭就小时
二级缓存是sessionFactory级别的缓存 一个应用程序只有一个 多个线程共享 不要把经常修改的对象放到二级缓存中 二级缓存中放一些查询的对象
1 首先是在hibernate,cfg.xml文件中进行配置:
添加下列配置项
- <property name="hibernate.cache.use_second_level_cache">true</property>
 - <!-- 使用哪种缓存提供的类 哪种缓存 -->
 - <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
 - <!-- 使用查询缓存-->
 - <property name="hibernate.cache.use_query_cache">true</property>
 - <!-- ehcache.xml的配置文件路径 -->
 - <property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
 
在需要使用二级缓存的对象配置文件上:
- <class name="Student" table="t_stu">
 - <!-- <cache usage="read-only" /> -->
 - <id name="id">
 - <generator class="native"></generator>
 - </id>
 - <!-- 注意:version 一定要加在ID后面 property前面 -->
 - <version name="version" />
 - <property name="name" />
 - <property name="sex" />
 - <many-to-one name="classroom" column="cid" fetch="join" />
 - </class>
 
ehcache.xml中的配置:
- <defaultCache
 - maxElementsInMemory="10000"
 - eternal="false"
 - timeToIdleSeconds="120"
 - timeToLiveSeconds="120"
 - overflowToDisk="true"
 - />
 
- <!-- 每一个独立的cache可以单独为不同的对象进行设置 如果找不到就用默认的cache-->
 - <cache name="com.itany.model.Student"
 - maxElementsInMemory="10000"
 - eternal="false"
 - timeToIdleSeconds="300"
 - timeToLiveSeconds="600"
 - overflowToDisk="true"
 - />
 
2 N+1问题
如果使用iterator返回列表 对于hibernate而言 
         它仅仅是查询了id列表的SQL 在进行iterator迭代的时候 
         再会根据id一个个去数据库查询具体对象 因此发出多条SQL 这就是典型的N+1问题 避免它
         就是不使用iterator iterator存在的原因 
         使用的地方:
         因为有可能需要查询2次 第一次list全部查询出来 存在二级缓存中 第二次 用Iterator数据库查id,再根据ID从二级缓存的对象中查询更快
- session = HibernateUtil.openSession();
 - Iterator<Student> it = session.createQuery("from Student").setFirstResult(0).setMaxResults(12).iterate();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 
3 重要:二级缓存缓存的是对象 查询缓存缓存的是ID 这是两种不同的缓存 谁也不依赖谁 查询缓存也是sessionFactory级别的缓存
查询缓存是针对HQL语句的缓存  查询缓只缓存ID 而不会缓存对象
     1 但是使用查询缓存最好打开二级缓存 因为在查询缓存中查到ID后可以直接去
     二级缓存中查找 不然的话又是N+1问题 多次根据查询缓存中的ID去数据库查询
     2 若打开了二级缓存 但是没有打开查询缓存(HQL不一致、参数不一致、查询缓存没开、
     setCacheable(true)没写等原因)那么还是会直接从数据库中查询一次、
     因为需要借助查询缓存查ID再到二级缓存中查对象
     3 注意:load方式可以直接从二级缓存中查对象 不必借助查询缓存
     4如果取得只是某些属性(而不是完整对象) 那么不会进行二级缓存见test04
     5 查询缓存 工作顺序:如果正常开启了查询缓存(HQL完全一致 且set(True)),先去查询缓存中查ID
          再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
         若二级缓存没打开  那么此时会再次根据查到的ID去数据库中查询
4 代码中使用查询缓存
- List<Object[]> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 
5 此时关闭了二级缓存(存对象)
    打开了查询缓存(存ID) 第二个人查询缓存只查到ID 会根据ID 去二级缓存查对象  但是没有  所以去数据库查  发出大量SQL
6 查询缓存很少使用 因为很少HQL完全一样
          因为只要HQL语句不一样 就不会开启查询缓存 
          只有两个完全一样的 并且参数都一样的 才能使用查询缓存
- public class TestSecondCache
 - {
 - /*
 - * 重要:二级缓存缓存的是对象 查询缓存缓存的是ID 这是两种不同的缓存
 - * 谁也不依赖谁
 - * 1 但是使用查询缓存最好打开二级缓存 因为在查询缓存中查到ID后可以直接去
 - * 二级缓存中查找 不然的话又是N+1问题 多次根据查询缓存中的ID去数据库查询
 - * 2 若打开了二级缓存 但是没有打开查询缓存(HQL不一致、参数不一致、查询缓存没开、
 - * setCacheable(true)没写等原因)那么还是会直接从数据库中查询一次、
 - * 因为需要借助查询缓存查ID再到二级缓存中查对象
 - * 3 注意:load方式可以直接从二级缓存中查对象 不必借助查询缓存
 - *
 - * 如果取得只是某些属性(而不是完整对象) 那么不会进行二级缓存见test04
 - */
 - @Test
 - public void test01()
 - {
 - /*
 - * 不可以缓存 Ehcache是看SQL是否一样
 - */
 - Session session = null;
 - try
 - {
 - session = HibernateUtil.openSession();
 - Student s=(Student)session.load(Student.class,1);
 - System.out.println(s.getName());
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - Session session2 = null;
 - /*
 - * 此时session已经关闭 但再次查询 仍然可以不发SQL 二级缓存起作用了
 - */
 - try
 - {
 - session2 = HibernateUtil.openSession();
 - Student s2=(Student)session2.load(Student.class,1);//这种写法 根据ID去二级缓存中查询
 - System.out.println(s2.getName());
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session2)
 - HibernateUtil.closeSession(session2);
 - }
 - }
 - @Test
 - public void test02()
 - {
 - /*
 - *
 - */
 - Session session = null;
 - try
 - {
 - session = HibernateUtil.openSession();
 - Student s=(Student)session.load(Student.class,1);
 - System.out.println(s.getName());
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - Session session2 = null;
 - Transaction trans=null;
 - /*
 - * 会报错 因为二级缓存 在Student上设置的是 read-only 因此不能写入
 - * 最好不要设置 read write因为hibernate要频繁的加锁 解锁 影响效率 还不如不用二级缓存
 - */
 - try
 - {
 - session2 = HibernateUtil.openSession();
 - trans=session2.beginTransaction();
 - Student s2=(Student)session2.load(Student.class,1);
 - s2.setName("zhangasnsss");
 - System.out.println(s2.getName());
 - trans.commit();
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session2)
 - HibernateUtil.closeSession(session2);
 - }
 - }
 - @Test
 - public void test03()
 - {
 - /*
 - *
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - {
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("from Student").list();
 - Iterator<Student> it = ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - try
 - {
 - session = HibernateUtil.openSession();
 - Student s=(Student)session.load(Student.class,1);
 - System.out.println(s.getName());
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test04()
 - {
 - /*
 - *
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - {
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu.id,stu.name from Student stu").list();
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*
 - * 以上代码仅仅去了id和name 而二级缓存是缓存对象的 所以上一段代码不会使用二级缓存
 - * 此时就会发出相应的SQL
 - */
 - try
 - {
 - session = HibernateUtil.openSession();
 - Student s=(Student)session.load(Student.class,1);
 - System.out.println(s.getName());
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test05()
 - {
 - /*
 - * iterator 作用就是配合二级缓存使用 最好
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu").list();
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /* 1条SQL
 - * 由于学生的对象经过上面查询对象之后 已经存在于二级缓存之中
 - * 此时正好直接使用iterator 首先会查询通过1条取ID的语句 然后再获取对象时候去二级缓存中查询
 - * 有的话 直接用 不会产生N+1问题
 - *
 - * 若没二级缓存 我们直接使用iterator会首先产生一条查ID的语句
 - * 再在获取对象的时候再去数据库中取 那么这是就会产生N+1问题
 - */
 - try
 - {
 - session = HibernateUtil.openSession();
 - Iterator<Student> it = session.createQuery("from Student").iterate();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test06()
 - {
 - /*
 - * 与上面一个几乎一样 区别在于iterator换成list()
 - * 虽然第一次已经二级缓存了 但是不能决定我再去不去数据库中查询
 - *
 - * 重要 :如果希望第二次不发SQL 那就要使用查询缓存
 - * 查询缓存是针对HQL语句的缓存 查询缓只缓存ID 而不会缓存对象
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu").list();
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /* 1条SQL 和上一条一模一样
 - *
 - */
 - try
 - {
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu").list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test07()
 - {
 - /*
 - * 设置了查询缓存为true
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu")
 - .setCacheable(true).list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*0条SQL
 - *
 - */
 - try
 - {
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu")
 - .setCacheable(true).list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test08()
 - {
 - /*
 - * 此时无法使用查询缓存 查询缓存很少使用 因为很少HQL完全一样
 - * 因为只要HQL语句不一样 就不会开启查询缓存
 - * 只有两个完全一样的 并且参数都一样的 才能使用查询缓存
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*
 - *
 - */
 - try
 - {
 - //一条SQL
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%王%").list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test09()
 - {
 - /*
 - * 此时关闭了二级缓存(存对象)
 - * 打开了查询缓存(存ID)
 - * !!!工作顺序:如果正常开启了查询缓存(HQL完全一致 且set(True)),先去查询缓存中查ID
 - * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
 - * 若二级缓存没打开 那么此时会再次根据查到的ID去数据库中查询
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*
 - *
 - */
 - try
 - {
 - //此时关闭了student的二级缓存 打开了查询缓存 发出大量SQL
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test10()
 - {
 - /*
 - * 此时打开了二级缓存(存对象)
 - * 打开了查询缓存(存ID)
 - * !!!!工作顺序:如果正常开启了查询缓存,先去查询缓存中查ID
 - * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
 - * 若二级缓存没打开 那么此时会再次根据查到的ID去数据库中查询
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*
 - *
 - */
 - try
 - {
 - //此时打开了student的二级缓存 打开了查询缓存 不发SQL
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - @Test
 - public void test11()
 - {
 - /*
 - * 此时打开了二级缓存(存对象)
 - * 打开了查询缓存(存ID)
 - * !!!!工作顺序:如果正常开启了查询缓存,先去查询缓存中查ID
 - * 再根据查询到的ID去二级缓存中查对象 若此时二级缓存打开了 那么不会发SQL
 - * 若二级缓存没打开 那么此时会再次根据查到的ID去数据库中查询
 - */
 - Session session = null;
 - Transaction trans = null;
 - try
 - { //一条SQL
 - session = HibernateUtil.openSession();
 - List<Object[]> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张%").list();//开启查询缓存 查询缓存也是sessionFactory级别的缓存
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - /*
 - *
 - */
 - try
 - {
 - //此时虽然打开了student的二级缓存 但是不能使用查询缓存(HQL不一致)导致没法通过查询缓存查ID去
 - //二级缓存中查对象
 - //所以仍然发出一条SQL 从数据库中查询
 - session = HibernateUtil.openSession();
 - List<Student> ls = session.createQuery("select stu from Student stu where name like ?")
 - .setCacheable(true).setParameter(0, "%张三%").list();
 - Iterator<Student> it=ls.iterator();
 - while (it.hasNext())
 - {
 - Student stu = it.next();
 - System.out.println(stu.getName());
 - }
 - }
 - catch (HibernateException e)
 - {
 - e.printStackTrace();
 - }
 - finally
 - {
 - if (null != session)
 - HibernateUtil.closeSession(session);
 - }
 - }
 - }
 
hibernate--一级和二级缓存(使用Ehcache)以及查询缓存的更多相关文章
- 说说自己对hibernate一级、二级、查询、缓存的理解。
		
说说自己对hibernate一级.二级.查询.缓存的理解. 2016-03-14 21:36 421人阅读 评论(0) 收藏 举报 分类: web开发(19) 版权声明:本文为博主原创文章,未经博 ...
 - mybatis中二级缓存整合ehcache实现分布式缓存
		
mybatis自带二级缓存,但是这个缓存是单服务器工作,无法实现分布式缓存.那么什么是分布式缓存呢?假设现在有两个服务器1和2,用户访问的时候访问了1服务器,查询后的缓存就会放在1服务器上,假设现在有 ...
 - ThinkPHP缓存技术(S(),F(),查询缓存,静态缓存)
		
直接查看原网址 https://blog.csdn.net/u010081689/article/details/47976271
 - hibernate缓存机制详细分析(一级、二级、查询缓存,非常清晰明白)
		
本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session级别).二级缓存(sessionFactory级别)以及查询缓存,当然还要讨论下我们的N+1的问题. 随笔虽长,但我相信 ...
 - [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存
		
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
 - Spring控制Hibernate的缓存机制ehcache
		
首先在spring.xml中进入bean <prop key="hibernate.cache.use_second_level_cache">true</pro ...
 - Hibernate中 一 二级缓存及查询缓存(1)
		
最近趁有空学习了一下Hibernate的缓存,其包括一级缓存,二级缓存和查询缓存(有些是参照网络资源的): 一.一级缓存 一级缓存的生命周期和session的生命周期一致,当前sessioin ...
 - 【Hibernate】 二级缓存及查询缓存
		
一.Hibernate的二级缓存 1.1 类缓存区特点 缓存的是对象的散装的数据. 图一 Hibernate的二级缓存的散装数据 1.2 集合缓存区的特点: 缓存的是对象的id.需要依赖类缓冲区的配置 ...
 - Java三大框架之——Hibernate中的三种数据持久状态和缓存机制
		
Hibernate中的三种状态 瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...
 
随机推荐
- 查看 nodejs 安装包的相关指令
			
npm -h 以上指令可以看到npm可用的指令 如果要卸载就用npm uninstall
 - 前向算法Python实现
			
前言 这里的前向算法与神经网络里的前向传播算法没有任何联系...这里的前向算法是自然语言处理领域隐马尔可夫模型第一个基本问题的算法. 前向算法是什么? 这里用一个海藻的例子来描述前向算法是什么.网上有 ...
 - Hadoop错误日志
			
1.错误日志:Directory /tmp/hadoop-root/dfs/name is in an inconsistent state: storage directory does not e ...
 - IHttpHandler IHttpModule
			
ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后,仍经过Pi ...
 - JVM堆内存调优
			
堆大小设置JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64为操作 ...
 - firefox、chrome的DNS缓存清除方法
			
通过设置hosts文件可以强制指定域名对应的IP,当修改hosts文件,想要浏览器生效,最直接的方法关闭浏览器后重新开启:如果不想重启浏览器,只需要清空浏览器的DNS缓存即可. 清空DNS缓存在chr ...
 - MyBatis各种类型的入参使用方式
			
https://blog.csdn.net/u011983531/article/details/53561219 mybatis中if判断传入字符串或者Long参数不为空 https://blog. ...
 - ubuntu 14.04 安装 glog
			
1.下载 git clone https://github.com/google/glog 2.配置 sudo apt-get install autoconf automake libtool 3. ...
 - MongoDB(课时7 逻辑运算)
			
3.4.2.2 逻辑运算 逻辑运算主要三种类型:与($and),或($or),非($not.$nor). 范例:查询年龄在20~21岁的学生信息 db.students.find({"age ...
 - VcCallC#_01
			
1.C# 代码: using System; using System.Collections.Generic; //using System.Linq; using System.Text; //u ...