您的位置:首页 > 编程语言 > Java开发

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

2017-04-12 18:18 260 查看
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():执行JPQL的select语句,并用一个List返回查询结果
2)Object getSingleResult():执行返回单个结果的select语句
如果需要分页,则调用Query的setFirstResult()、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属性,前提是Person和Teacher完成了正确的继承映射
通过JPQL查询返回的List到底包括多少个集合元素,其实是根据底层SQL语句中来决定的,底层SQL语句查询结果有几条记录,JPQL查询返回的List就包含几个集合元素。每个List集合元素对应SQL查询的一条记录,JPA会负责将每条记录转换为一个数组。
对于1-1、N-1关联关系而言,当前实体若只有一个与之关联的关联实体,加载当前实体的同时也加载关联实体不会有太大的性能问题,因此1-1、N-1关联可以不使用延迟加载,因此@OneToOne、@ManyToOne的fetch属性的默认值是FetchType.EAGER;但对于1-N、N-N而言,当前实体可能有大量与之关联的关联实体,加载当前实体的同时加载所有关联实体可能引起性能低下,因此1-N、N-N关联通常都会设置延迟加载。因此@OneToMany、@ManyToMany的fetch属性的默认值是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 by与order 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(?,?,...)}
如果存储过程返回了全部数据列,就可以将结果映射成实体
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: