Hibernate---QBC查询(1)

一.条件查询

条件查询是根据面向对象特色的数据查询方式,条件查询通过如下三个类完成:

1>Criteria:代表一次查询

2>Criterion:代表一个查询条件

3>Restrictions:产生查询条件的工具类

执行条件查询的步骤如下:

1>获得Hibernate的Session对象

2>以Session对象创建Criteria对象

3>使用Restrictions的静态方法创建Criterion查询条件

4>向Criteria查询中添加Criterion查询条件

5>执行Criteria的list()或uniqueResult()方法返回结果集

程序示例如下:

方法1:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Student.class)
				.add(Restrictions.gt("name", "cname")).list();
		for(Object obj : list){
			Student s = (Student)obj;
			System.out.println(s.getName());
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>

方法2:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List<Student> list = sess.createCriteria(Student.class)
				.add(Restrictions.gt("name", "cname")).list();
		for(Student s : list){
			System.out.println(s.getName());
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
注意:方法1的List不带泛型信息,需要进行显示的数据类型转换,方法2的List带泛型信息,可以直接使用;

在SQL语句中,字符串之间可以比较大小;

Criteria包含如下五个方法:

1>Criteria setFirstResult(int firstResult):设置查询返回的第一行记录(索引从0开始);

2>Criteria setMaxResult(int maxResult):设置查询返回的记录数;

这两个方法与Query的两个类似方法的功能一样,都用于完成查询分页;

3>Criteria add(Criterion criterion):增加查询条件

4>Criteria addOrder(Order order):增加排序规则,例如addOrder(Order.desc("type"));

    Order实例代表一个排序标准,Order有如下静态方法:

    4-1>static Order asc(String propertyName):根据propertyName属性升序排列

    4-2>static Order desc(String propertyName):根据propertyName属性降序排列

5>List list():返回结果集

Criterion接口代表一个查询条件,该查询条件由Restrictions负责产生,Restrictions是专门用于产生查询条件的工具类,他的方法大部分都是静态方法,常用的方法如下:

1>static eq | ne | gt | ge | lt | le(String propertyName,Object value)

判断指定属性值是否等于,不等于,大于,大于等于,小于,小于等于指定值

2>static eq | ne | gt | ge | lt | leProperty(String propertyName,String otherPropertyName)

判断第一个属性(由propertyName参数决定)的值是否等于,不等于,大于,大于等于,小于,小于等于第二个属性(由otherPropertyName参数确定)的值

3>static Criterion allEq(Map propertyNameValues)

判断指定属性(由Map参数的key指定)和指定值(由Map参数的value指定)是否完全相等

注意:Map必须是Map<String,T>类型的,String是字段名称,T是该字段的值,每一个map存放的多个键值对只对应书记表同一条数据记录

4>static Criterion between(String propertyName,Object lo,Object hi)

判断属性值在某个值范围之内

5>static Criterion ilike(String propertyName,Object value)

判断属性值匹配某个字符串,不区分大小写,条件字符串要不是完整的字符串去匹配,要不采用%通配符进行匹配

6>static Criterion ilike(String propertyName,String value,MatchMode matchMode)

判断属性值匹配某个字段,不区分大小写,模式是以判断以某个字符串开头或者结尾等,这个匹配字符串可以是整个值的字符串,也可以是其中的一部分,也可以使用%通配符

7>static Criterion like(String propertyName,Object value)

判断属性值匹配某个字符串,区分大小写,条件字符串要不是完整的字符串去匹配,要不采用%通配符进行匹配(理论上这个匹配区分大小写,但是实际测试不区分,和ilike一样)

8>static Criterion like(String propertyName,String value,MatchMode matchMode)

判断属性值匹配某个字段,区分大小写,模式是以判断以某个字符串开头或者结尾等,这个匹配字符串可以是整个值的字符串,也可以是其中的一部分,也可以使用%通配符(理论上这个匹配区分大小写,但是实际测试不区分,和ilike一样)

9>static Criterion in(String propertyName,Collection values)

判断属性值在在某个集合内

10>static Criterion in(String propertyName,Object[ ] values)

判断属性值是数组元素的其中之一

11>static Criterion isEmpty(String propertyName)

判断属性值是否为空,这个测试出错,暂时不知道这个方法的应用场景,应该是涉及到关联的集合

12>static Criterion isNotEmpty(String propertyName)

判断属性值是否不为空,这个测试出错,暂时不知道这个方法的应用场景,应该是涉及到关联的集合

13>static Criterion isNull(String propertyName)

判断属性值是否为空

14>static Criterion isNotNull(String propertyName)

判断属性值是否不为空

15>static Criterion not(Criterion expression)

对Criterion求反,两个条件进行嵌套,例如.add(Restrictions.not(Restrictions.eq("name", "cname")))

16>static Criterion sizeEq(String propertyName,int size)

判断某个属性的元素个数是否与size相等,这个测试出错,暂时不知道这个方法的应用场景,应该是涉及到关联的集合

17>static Criterion sqlRestriction(String sql)

直接使用sql语句作为筛选条件,例如:.add(Restrictions.sqlRestriction("type > 15"))

18>static Criterion sqlRestriction(String sql,Object[ ] values,Type[ ] types)

直接使用带参数占位符的SQl语句作为条件,并指定多个参数值,例如.add(Restrictions.sqlRestriction("type > ? and id > ?",new String[]{"17","17"},new Type[]{StringType.INSTANCE,StringType.INSTANCE}))

19>static Criterion sqlRestriction(String sql,Object value,Type type)

直接使用带参数占位符的SQl语句作为条件,并指定参数值,例如.add(Restrictions.sqlRestriction("type > ?","17",StringType.INSTANCE))

===========================================================

二.关联和动态关联

如果需要使用关联实体的属性来增加查询条件,则应该对属性再次使用createCriteria()方法,createCriteria()方法有如下重载版本:

1>Criteria createCriteria(String associationPath):使用默认的连接方式进行关联

2>Criteria createCriteria(String associationPath,JoinType joinType):以JoinType指定的连接方式进行关联;支持INNER_JOIN、LEFT_OUTER_JOIN、RIGHT_OUTER_JOIN、FULL_JOIN等枚举值;

3>Criteria createCriteria(String associationPath,String alias):该方法的功能与第一个方法的功能基本相似,只是该方法允许为关联实体指定别名;

4>Criteria createCriteria(String associationPath,String alias,JoinType joinType):该方法的功能与第二个方法的功能基本相似,只是该方法允许为关联实体指定别名;

5>Criteria createCriteria(String associationPath,String alias,JoinType joinType,Criterion withClause):该方法的功能最强大,该方法既可为关联实体指定别名,也可指定连接类型,还可以通过withClause指定自定义的连接条件---这个可用于实现非等值连接;

对比上面的方法,他们功能基本相似,只是有的能显示指定连接方式;

如下示例根据关联实体的属性过滤数据:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Student.class)
				//此处增加限制条件必须是Student实体存在的属性
				.add(Restrictions.gt("studentNumber", 20050231))
				//如果要增加对Student的关联类的属性限制
				//必须重载createCriteria()
				//如果此关联属性是集合,则只要集合里任意一个对象的属性满足下面条件即可
				.createCriteria("enrolments")
				.add(Restrictions.eq("semester", 4)).list();
		for(Object obj:list){
			Student s = (Student)obj;
			System.out.println(s.getName());
			System.out.println(s.getEnrolments().size());
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
使用关联类的条件查询,依然是查询原有持久化类的实例,而不是查询被关联类的实例;


为了达到上面这种效果,也可以使用createAlias()方法来代替createCriteria()方法,createAlias()方法同样有三个重载的版本:

1>Criteria createAlias(String associationPath,String alias):该方法的功能基本等同于Criteria createCriteria(String associationPath,String alias);

2>Criteria createAlias(String associationPath,String alias,JoinType joinType):该方法的功能基本等同于Criteria createCriteria(String associationPath,String alias,JoinType joinType)

3>Criteria createAlias(String associationPath,String alias,JoinType joinType,Criterion withClause):该方法的功能基本等同于Criteria createCriteria(String associationPath,String alias,JoinType joinType,Criterion withClause);

因此,程序可以将上面的查询替换为如下形式:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Student.class)
				//此处增加限制条件必须是Student实体存在的属性
				.add(Restrictions.gt("studentNumber", 20050231))
				//如果要增加对Student的关联类的属性限制
				//必须重载createCriteria()
				//如果此关联属性是集合,则只要集合里任意一个对象的属性满足下面条件即可
				.createAlias("enrolments","al")
				.add(Restrictions.eq("al.semester", 4)).list();
		for(Object obj:list){
			Student s = (Student)obj;
			System.out.println(s.getName());
			System.out.println(s.getEnrolments().size());
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
createAlias()方法并不是创建一个新的Criteria实例,他只是给关联实体(包括集合里包含的关联实体)起一个别名,让后面的过滤条件可根据该关联实体进行筛选;

在默认情况下,条件查询将根据持久化注解指定的延迟加载策略来加载关联实体,如果希望在条件查询中改变延迟加载策略(就像HQl查询中使用fetch关键字一样),则可以通过Criteria的setFetchMode()方法来实现,该方法也接受一个FetchMode枚举类型的值,FetchMode支持如下枚举值:

1>DEFAULT:使用配置文件指定延迟加载策略处理;

2>JOIN:使用外连接,预初始化所有的关联实体;

3>SELECT:启用延迟加载,系统将使用单独的select语句来初始化关联实体,只有当真正访问关联实体的时候,才会执行第二条select语句;

如果想让程序在初始化Student对象时,也可以初始化Student关联的Enrolment实体,则可使用如下查询方法

<span style="font-size:18px;"><strong>public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Student.class)
				//此处增加限制条件必须是Student实体存在的属性
				.add(Restrictions.gt("studentNumber", 20050231))
				.setFetchMode("enrolments", FetchMode.JOIN)
				.list();
		tx.commit();
		HibernateSessionFactory.closeSession();
		for(Object obj:list){
			Student s = (Student)obj;
			System.out.println(s.getName());
			System.out.println(s.getEnrolments().size());
		}
	}</strong></span>
上面程序的setFetchMode()方法将会初始化Student关联的enrolments集合,由于这个方法让程序查询Student实体时同步抓取了Student关联的Enrolemnt实体,虽然程序在HibernateSeeionFactory.closeSession处关闭了session,但程序依然可以在下面通过Student获取关联的Enrolment实体。如果程序将这个方法注释掉,程序会在下面的调用中引发LazyInitializationException异常(延迟初始化异常),导致该异常的典型原因就是,当程序试图获取延迟加载的关联实体或集合属性时,Session的关闭导致无法加载到关联实体或集合属性,程序就会引发LazyInitializationException异常了;

===========================================================

三.投影、聚合和分组

投影运算实际上就是一种基于列的运算,通常用于投影到指定列(也就是过滤其他列,类似于select子句的作用),还可以完成sql语句中常用的分组,组筛选等功能;

Hibernate的条件过滤中使用Projection代表投影运算,Projection是一个接口,而Projections作为Projection的工厂,负责生成Projection对象;

一旦产生了Projection对象之后,就可以通过Criteria提供的setProjection(Projection projection)方法来进行投影运算,从该方法上来看,每个Criteria只能接收一个投影运算,似乎无法进行多个投影运算,但实际上,hibernate又提供了一个ProjectionList类,该类是Projection的子类,并可以包含多个投影运算,通过这种方式即可完成多个投影运算;

因此,一个条件查询的投影运算通常有如下程序结构:

List cats = session.createCriteria(Cat.class)

.setProjection(Projections.projectionList()

.add(Projections.rowCount())

.add(Projections.avg("weight"))

.add(Projections.max("weight"))

.add(Projections.min("weight"))

.add(Projections.groupProperty("color")))

.list();

从上面的粗体字代码可以看出,所谓投影运算实际上和sql语句里的聚集函数,分组语句(group by子句)有类似的功能,使用条件查询的投影运算时,不能使用显示的分组子句,但某些投影的类型的实质就是分组投影,这些投影运算将会出现在sql语句的group by子句中,如上面的groupProperty("color")投影;

在Projections工具类提供了如下几个静态方法:

1>AggregateProjection avg(String propertyname):计算特定属性的平均值,类似于avg函数;

2>CountProjection count(String propertyname):统计查询结果在某列上的记录条数,类似于count(column)函数;

3>CountProjection countDistinct(String propertyname):统计查询结果在某列上不重复的记录条数,类似于count(distinct column)函数;

4>PropertyProjection groupProperty(String propertyname):将查询结果按某列上的值进行分组,类似于添加group by子句;

5>AggregateProjection max(String propertyname):统计查询结果在某列上的最大值,类似于max函数;

6>AggregateProjection min(String propertyname):统计查询结果在某列上的最小值,类似于min函数;

7>Projection rowCount():统计查询结果的记录条数,类似于count(*)的功能;

8>AggregateProjection sum(String propertyname):统计查询结果在某列上的总和,类似于sum函数;

下面的程序示范如何通过投影运算来进行分组,使用聚集函数功能:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.createAlias("student", "s")
				.setProjection(Projections.projectionList()
						//统计记录条数
						.add(Projections.rowCount())
						//统计选择该课程里最大的学生姓名
						.add(Projections.max("s.name"))
						//按照course进行分组
						.add(Projections.groupProperty("course")))
				.list();
		for(Object obj:list){
			Object[] objs = (Object[])obj;
			Course c = (Course)objs[2];
			System.out.println(c.getName());
			System.out.println(objs[0]);
			System.out.println(objs[1]);
			System.out.println("------------");
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
		
	}</strong></span>
上面程序为条件查询增加了分组功能,并通过Projections统计了每组的记录条数,统计Student名字最大的值;

从上面的程序可以看出,对于增加了投影运算后的条件查询,查询返回的结果是数组,数组的前N个元素依次是投影运算的结果,最后一个数组元素才是条件查询得到的实体,由此可见,投影运算的实质和group by子句,聚集函数的功能大致一致;

除此之外,如果希望对分组(投影)后的属性进行排序,那就需要为投影运算指定一个别名,为投影运算指定别名有如下三个方法:

1>使用Projections的alisa()方法为指定投影指定别名;

Projections的alias()方法为指定Projection指定别名,并返回Projection对象,一旦为指定Projection指定了别名,程序就可以根据该Projection别名来进行其他操作了,比如排序,条件查询示例如下

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.createAlias("student", "s")
				.setProjection(Projections.projectionList()
						//统计记录条数
						.add(Projections.rowCount())
						//统计选择该课程里最大的学生姓名,如果以这个为别名进行排序,原来的这个投影查询条件运算不能省略
						.add(Projections.max("s.name"))
						//按照course进行分组
						.add(Projections.groupProperty("course"))
						.add(Projections.alias(Projections.max("s.name"), "s")))
				.addOrder(Order.asc("s"))
				.list();
		for(Object obj:list){
			Object[] objs = (Object[])obj;
			Course c = (Course)objs[2];
			System.out.println(c.getName());
			System.out.println(objs[0]);
			System.out.println(objs[1]);
			System.out.println("------------");
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
上面程序示范了为Projection指定别名的方法;

2>使用SimpleProjection的as()方法为自身指定别名;

如果条件查询所使用的投影运算是SimpleProjection及其子类,则可以直接使用该投影对象的as()方法来为自身指定别名,条件查询如下:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.createAlias("student", "s")
				.setProjection(Projections.projectionList()
						//统计记录条数
						.add(Projections.rowCount())
						//统计选择该课程里最大的学生姓名,如果以这个为别名进行排序,原来的这个投影查询条件运算不能省略
						.add(Projections.max("s.name").as("s"))
						//按照course进行分组
						.add(Projections.groupProperty("course")))
				.addOrder(Order.asc("s"))
				.list();
		for(Object obj:list){
			Object[] objs = (Object[])obj;
			Course c = (Course)objs[2];
			System.out.println(c.getName());
			System.out.println(objs[0]);
			System.out.println(objs[1]);
			System.out.println("------------");
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>

3>使用ProjectionList的add()方法添加投影时指定别名;

ProjectionList的add()方法有两种重载形式:一种是直接添加一个投影,另一种是在添加投影时指定别名,示例如下:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.createAlias("student", "s")
				.setProjection(Projections.projectionList()
						//统计记录条数
						.add(Projections.rowCount())
						//统计选择该课程里最大的学生姓名,如果以这个为别名进行排序,原来的这个投影查询条件运算不能省略
						.add(Projections.max("s.name"),"s")
						//按照course进行分组
						.add(Projections.groupProperty("course")))
				.addOrder(Order.asc("s"))
				.list();
		for(Object obj:list){
			Object[] objs = (Object[])obj;
			Course c = (Course)objs[2];
			System.out.println(c.getName());
			System.out.println(objs[0]);
			System.out.println(objs[1]);
			System.out.println("------------");
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
除此之外,hibernate还提供了Property执行投影运算,Property投影的作用类似于sql语句中的select,条件查询的结果只有被Property投影的列才会被选出,示例如下:

如果只选择显示一列:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.setProjection(Property.forName("semester"))
				.list();
		for(Object obj:list){
			
			System.out.println(obj);
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
上面的条件查询执行的结果不在是对象集合,而是semester属性所组成的集合;

如果选择显示多列:

<span style="font-size:18px;"><strong>	public void Query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//使用createCriteria开始条件查询
		List list = sess.createCriteria(Enrolment.class)
				.setProjection(Projections.projectionList()
						.add(Property.forName("semester"))
						.add(Property.forName("year")))
				.add(Property.forName("name").eq("ss"))
				.list();
		for(Object obj:list){
			
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
上面的代码最后还能添加过滤条件,比如上面是name属性等于ss的记录

===========================================================

四.离线查询和子查询

条件查询的离线查询由DetachedCriteria来代表,DetachedCriteria类允许在一个Session范围之外创建一个查询,并且可以使用任意Session来执行它;

使用DetachedCriteria来执行离线查询,通常使用如下的方法来获得一个离线查询:

//创建指定持久化类的离线查询

DetachedCriteria.forClass(Class entity)

除此之外,DetachedCriteria还可代表子查询,当把DetachedCriteria传入Criteria中作为查询条件时,DetachedCriteria就变成了子查询,条件实例包含子查询通过Subqueries或者Property来获得;

如下程序示范了使用DetachedCriteria进行离线查询和子查询:

离线查询:

<span style="font-size:18px;"><strong>	public void Query(){
		//定义一个离线查询
		DetachedCriteria query = DetachedCriteria.forClass(Student.class)
				.setProjection(Property.forName("name"));
		//打开Session和事务
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//执行离线查询
		List list = query.getExecutableCriteria(sess).list();
		for(Object obj:list){
			System.out.println(obj);
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
子查询:

<span style="font-size:18px;"><strong>	public void Query(){
		//定义一个离线查询
		DetachedCriteria query = DetachedCriteria.forClass(Student.class)
				.setProjection(Property.forName("name"));
		//打开Session和事务
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		//执行子查询
		List<Student> list = sess.createCriteria(Student.class)
				//下面两行代码作用相同,都示范了通过子查询添加查询条件
				//.add(Property.forName("name").in(query))
				.add(Subqueries.propertyIn("name", query))
				.list();
		for(Student obj:list){
			System.out.println(obj.getName());
		}
		tx.commit();
		HibernateSessionFactory.closeSession();
	}</strong></span>
从上面的程序来看,当创建一个DetachedCriteria对象之后,该对象到底被作为离线查询使用还是作为子查询使用,都与DetachedCriteria无关;

如果程序使用Session的getExecutableCriteria()方法来执行DetachedCriteria对象,则他被当成离线查询使用,如果程序使用Property(或Subqueries的系列类方法)来操作DetachedCriteria对象,则他被当作子查询使用;

Property类提供了eq()、eqAll、ge()、geAll()、gt()、gtAll()、in等系列方法,这些方法与SQL子查询中的运算符一一对应,除此之外,Subqueries也提供了eq()、eqAll、ge()、geAll()、gt()、gtAll()、in等静态方法,这些方法与Property同名的实例方法的功能基本相似,在这种情况下,DetachedCriteria被当成子查询使用;

-----------------------------------------------------------------

补充1:

	public static void query(){
		Session sess = HibernateSessionFactory.getSession();
		Transaction tx = sess.beginTransaction();
		Criteria criteria = sess.createCriteria(User.class,"user");
		criteria.createCriteria("institution","institution");
		ProjectionList pList = Projections.projectionList();
		pList.add(Property.forName("user.id").as("aa"))
			.add(Projections.property("user.username").as("bb"))
			.add(Projections.property("institution.institutionName").as("cc"));
		criteria.setProjection(pList);
		criteria.setResultTransformer(Transformers.aliasToBean(Temp.class));
		List list = criteria.list(); 
		tx.commit();
		HibernateSessionFactory.closeSession();
	}

这个方法的含义是:

1>查询User类的指定字段;

2>查处的结果使用setResultTransformer方法进行规整,必须有一个Temp的类去接收指定的字段,如下:

package com.anlw.entity;

public class Temp {
	private int aa;
	private String bb;
	private String cc;
	public int getAa() {
		return aa;
	}
	public void setAa(int aa) {
		this.aa = aa;
	}
	public String getBb() {
		return bb;
	}
	public void setBb(String bb) {
		this.bb = bb;
	}
	public String getCc() {
		return cc;
	}
	public void setCc(String cc) {
		this.cc = cc;
	}
	
}


3>Property.froName()方法与Projections.property()方法的作用一样,都是指定自定义查询的字段;













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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值