【JavaEE】经典JAVA EE企业应用实战-读书笔记18

JPA定义了一套属于面向对象的查询语言,Java Presistence Query Languate(JPQL),可以在多种数据库上运行良好

Query接口就是JPQL的核心API。由EntityManager创建出来,提供了以下的方法

1)Query createNamedQuery(String name):创建查询的名称来创建一个命名查询。可以用JPQL定义也可以用SQL定义

2)Query createNativeQuery(String sqlString):根据原生SQL来创建一个查询

3)Query createNativeQuery(String sqlString,Class resultClass)

4)Query createNativeQuery(String sqlString,String resultSetMapping):其中resultSetMapping用于对结果集进行自定义映射。

5)Query createQuery(String jpqlString):根据指定的JPQL语句来创建一个查询

JPQL语句中既可以使用问号(?N,其中N代表位置索引)作为索引参数,也可以使用命名参数,而Query则提供如下方法来为JPQL语句中参数设置参数值

1)Query setParameter(int position,Calendar value,TemporalType temporalType):根据参数的位置索引为JPQL语句中的日期、时间类型的参数设置参数值。其中第三个参数指定到底需要哪种类型的参数值

2)Query setParameter(int position,Date value,TemporalType temporalType):根据参数的位置索引为JPQL语句中的日期、时间类型的参数设置参数值。其中第三个参数指定到底需要哪种类型的参数值

3)Query setParameter(int position,Object value):根据参数的位置索引为JPQL语句中的参数设置参数值

4)Query setParameter(String name,Calendar value,TemporalType temporalType):根据命名参数的名称为JPQL语句中的日期、时间类型的参数设置参数值。其中第三个参数指定到底需要哪种类型的参数值

5)Query setParameter(String name,Date value,TemporalType temporalType):根据命名参数的名称为JPQL语句中的日期、时间类型的参数设置参数值。其中第三个参数指定到底需要哪种类型的参数值

6)Query setParameter(String name,Object value):根据命名参数的名称为JPQL语句中的参数设置参数值

通过多次调用上面的方法设置参数值后,调用Query的如下方法执行查询

1)List getResultList():执行JPQLselect语句,并用一个List返回查询结果

2)Object getSingleResult():执行返回单个结果的select语句

如果需要分页,则调用QuerysetFirstResult()setMaxResults()方法进行设置

 

select news,news.title,news.content from News as news where news.id>?1 and news.title not like :title

上面的JPQL语句中,第一个参数用问号(?1)表示,这个参数代表一个位置参数;第二个参数用:title表示,这个参数代表一个命名参数

一般情况下很少会在JPQL语句中同时使用位置参数和命名参数

一般使用位置参数具有较好的性能,但可读性差一些。命名参数有较好的可读性,但性能略低一些,不过这些区别几乎可以忽略不计

query.setParameter(1,1).setParameter(“title”,”%Java%”);

对于Query对象的getResultList()方法来获取查询结果时,程序返回一个List集合(具体是List的哪种实现则取决于JPA实现,对于Hibernate JPA实现而言,底层通常是一个ArrayList集合;对于TopLink JPA实现而言,底层是一个线程安全的Vector集合)

List集合返回的元素是一个Object[]数组,其长度和查询中select语句列出的条目相同

select p.name,p from Person as p

查询结果类似于[String,Person]结构的数组

select new ClassTest(p.name,p.address) from Person as p

可以用构造器创建实例,前提是ClassTest中有这样的构造器

 

select cat from Cat cat where cat.mate.name like “kit%”

上面的语句会转化为

select * from cat_table as table1 cat_table as table2

where table1.mate=table2.id and table2.name like “kit%”

 

select p.name from Person p

该查询不仅会查询出Person的全部实例的name属性,还会查询出Person的子类实例的name属性,如Teacher的全部实例的name属性,前提是PersonTeacher完成了正确的继承映射

通过JPQL查询返回的List到底包括多少个集合元素,其实是根据底层SQL语句中来决定的,底层SQL语句查询结果有几条记录,JPQL查询返回的List就包含几个集合元素。每个List集合元素对应SQL查询的一条记录,JPA会负责将每条记录转换为一个数组。

对于1-1N-1关联关系而言,当前实体若只有一个与之关联的关联实体,加载当前实体的同时也加载关联实体不会有太大的性能问题,因此1-1N-1关联可以不使用延迟加载,因此@OneToOne@ManyToOnefetch属性的默认值是FetchType.EAGER;但对于1-NN-N而言,当前实体可能有大量与之关联的关联实体,加载当前实体的同时加载所有关联实体可能引起性能低下,因此1-NN-N关联通常都会设置延迟加载。因此@OneToMany@ManyToManyfetch属性的默认值是FetchType.LAZY

为了强制JPQL在执行查询时放弃延迟加载,可以在join关键字后使用fetch关键字,如

select p from Person as p

left join fetch p.address ad

where p.age>?1 or p.age<?2


查询返回的集合可以根据实体或复合属性的任何属性进行排序。

select p from Person as p order by p.name,p.age

select p from Person as p order by p.name asc,p.age desc

having子句用于对分组进行过滤,having子句只能在有group by子句时才可以使用

group byorder by子句中都不能包含算术表达式

 

Query接口提供了以下两个方法用于分页

setFirstResult:设置查询从第几条记录开始

setMaxResults:设置查询最多返回的记录条数

 

有经验的开发者往往会使用一个或几个接口来集中定义所有的SQL查询语句,而不是将SQL语句随意地放在应用程序中定义。

@Entity
@Table(name=”person_table”)
@NamedQuery(name=”personQuery”,query=”select p.name,p.address”+
    “ from Person as p where p.age>?1”)
public class Person{
    ...
}

JPA执行原生SQL查询时不会跟踪托管实体的状态,所以应该避免在原生SQL中使用插入、更改和删除语句。

 

使用原生SQL查询映射实体

@SqlResultSetMappings中包含多个@SqlResultSetMapping,后者用于定义一个结果集映射。

@SqlResultSetMapping的属性

1)name,必输,指定结果集映射的名称

2)entities,非必输,映射一个或多个实体,包含一个或多个@EntityResult

@EntityResult的属性

a)entityClass,必输,指定映射结果集的实体类的类名

b)DiscriminatorColumn,非必输,指定查询的数据列中作为辨别者的列名,只有在查询的数据表中使用了继承映射时才需要指定该属性

c)fields,非必输,用于将选出的数据列映射成实体的属性,包含一个或多个@FieldResult

@FieldResult的属性

1)column,必须,指定哪个数据列映射到实体的指定属性

2)name,必须,指定数据列映射到实体的哪个属性

3)columns,非必输,指定查询结果应该包含该属性所列出的数据列,包括一个或多个@ColumnResult

@ColumnResult的属性

a)name,必输,指定数据列的名称

例如:

@Entity
@Table(name=”news_table”)
@SqlResultSetMapping(
	name=”news_mapping”,
	entities={
		@EntityResult(
			entityClass=com.kingdz.model.News.class,
			fields={
				@FieldResult(name=”id”,column=”id”),
				@FieldResult(name=”title”,column=”news_title”),
				@FieldResult(name=”content”,column=”content”)
			}
		)
	}
	columns={
		@ColumnResult(name=”news_title”),
		@ColumnResult(name=”content”)
	}
)
public class News{
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;

	@Column(name=”news_title”,length=50)
	private String title;

	@Column(nullable=true)
	private String content;
	...
}


使用注解也可以定义原生SQL查询

@NamedNativeQuery的属性

1)name,必须,指定命名的原生SQL查询的名称

2)query,必须,指定原生SQL查询字符串

3)resultClass,非必须,指定一个实体类的类名,用于映射该实体类的实例

4)resultSetMapping:非必须,指定一个SQL映射的名称,使用该查询结果来处理查询结果集

例如:

@Entity
@Table(name=”news_table”)
@NamedNativeQuery(
	name=”news_query”,
	query=”select id,news_title,content from news_table where id > ?”,
	resultSetMapping=”news_mapping”
)
@SqlResultMapping(
	name=”news_mapping”,
	...
)
public class News{
	...
}
 

JPQL允许通过Query来调用存储过程,通过createNativeQuery方法来实现,需要传入参数为:

{call procedure_name(?,?,...)}

如果存储过程返回了全部数据列,就可以将结果映射成实体

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值