Spring JPA hibernate的认识
最近在做一个新项目,项目中用的不是最原始的sping、hibernate配置文件的形式,用的是全注解的形式。刚开始还不知道jpa是什么东西,干什么用的。
现在对它有了初步的认识,简单记录一下。
查看jpa和hibernate的区别可参考:http://blog.sina.com.cn/s/blog_5f1619e80100yoxz.html。
jpa是一种规范,hibernate是jpa的一种实现。
jpa可以简单的操作数据库对象。
第一步:先有实体类NetPoolE,为了实现对象和表的映射,我们省掉NetPoolE.hbm.xml的配置文件,我们使用jpa的注解:javax.persistence.Entity、Column、ID、GeneratedValue等。(不写注解,默认属性名和表的列名相同)例如:
@Entity(name = "NetPool")
public class NetPoolE {
/**
* 主键 网络池Id
*/
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
@Column(name = "netPoolId")
private String netPoolId;
/**
* 网络名称
*/
@Column(name = "netName", length = 255)
private String netName;
/**
* vlan号
*/
@Column(name = "vlanNo")
private Integer vlanNO;
/**
* 网关
*/
@Column(name = "gateway", length = 255)
private String gateway;
/**
* 子网
*/
@Column(name = "subNet", length = 255)
private String subNet;
/**
* dns
*/
@Column(name = "dns", length = 255)
private String dns;
/**
* 同步时间
*/
private Date synDate;
/**
* 是否可用
*/
private Boolean isAvl;
/**
* 组织Id
*/
private String ogrId;
public Date getSynDate() {
return synDate;
}
public void setSynDate(Date synDate) {
this.synDate = synDate;
}
public Boolean getIsAvl() {
return isAvl;
}
public void setIsAvl(Boolean isAvl) {
this.isAvl = isAvl;
}
public String getNetPoolId() {
return netPoolId;
}
public void setNetPoolId(String netPoolId) {
this.netPoolId = netPoolId;
}
public String getNetName() {
return netName;
}
public void setNetName(String netName) {
this.netName = netName;
}
public Integer getVlanNO() {
return vlanNO;
}
public void setVlanNO(Integer vlanNO) {
this.vlanNO = vlanNO;
}
public String getGateway() {
return gateway;
}
public void setGateway(String gateway) {
this.gateway = gateway;
}
public String getSubNet() {
return subNet;
}
public void setSubNet(String subNet) {
this.subNet = subNet;
}
public String getDns() {
return dns;
}
public void setDns(String dns) {
this.dns = dns;
}
public String getOgrId() {
return ogrId;
}
public void setOgrId(String ogrId) {
this.ogrId = ogrId;
}
@Override
public String toString() {
return "NetPoolE [netPoolId=" + netPoolId + ", netName=" + netName + ", vlanNO=" + vlanNO + ", gateway="
+ gateway + ", subNet=" + subNet + ", dns=" + dns + ", synDate=" + synDate + ", isAvl=" + isAvl
+ ", ogrId=" + ogrId + "]";
}
第二步:写jpa接口。之前都是写dao层的操作数据库对象,现在是使用jpa接口操作数据库对象,在dao层再调用jpa接口,service层再调用dao。
这里主要介绍jpa接口的定义。
自定义的jpa接口可以extends JpaRepository接口,该接口中有默认的一些方法。在dao层之间使用即可。
jpa支持一些通用的方法名,例如:findAll()查询所有,findAll(Pageable pageable)分页查询,findByPropertyNameContainingAllIgnoringCase(String name,Pageable pageable)模糊匹配分页查询,save(Entity e)保存对象等等。
jpa除了支持一些通用的方法名外,还支持自定义查询、关联查询等,例如:
interface HotelRepository extends Repository<Hotel, Long> {
Hotel findByCityAndName(City city, String name);
@Query("select new com.test.demo.data.jpa.entity.HotelSummary(h.city, h.name, avg(r.rating)) from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select new com.test.demo.data.jpa.entity.RatingCount(r.rating, count(r)) from Review r where r.hotel = ?1 group by r.rating order by r.rating DESC")
List<RatingCount> findRatingCounts(Hotel hotel);
}
修改语句:
@Modifying(clearAutomatically=true)
@Query("update NetPool np set np.gateway=?2, np.subNet=?3, np.dns=?4 where np.netPoolId=?1")
void updateNetPool(String poolId, String gateway, String subNet, String dns);
从此处开始是摘抄:
Spring Data Jpa 使用@Query标注自定义查询语句:
可参考http://www.tianmaying.com/tutorial/spring-jpa-query。
基础对象
Spring Data Jpa所提供的通过方法名进行查询的功能已经能够覆盖绝大多数单表查询了。但是,我们的查询绝不仅限于单表查询,很多时候我们还是需要进行多表查询的,因此我们今天设计两个表,blog
以及user
,通过这两个表的联合查询来试验@Query
标注。
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String username;
private String role;
......
}
@Entity
public class Blog {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String title;
private String content;
@ManyToOne
private User creator;
......
}
关联查询
blog表和user表通过creator相关联。在user表中,我们设计了一个属性角色--role
。如果我们想找到某种角色的用户所创建的blog列表应该怎么办?让我们通过@Query
标注去实现它吧:
public interface BlogRepository extends PagingAndSortingRepository<Blog, Integer> {
@Query("select blog from Blog blog join blog.creator creator where creator.role = ?1")
Page<Blog> findByRole(String role, Pageable pageable);
}
在BlogRepository中,我们通过@Query标注使用了HQL进行查询,通过它,我们可以更加灵活的进行各种查询(当然,Spring Data JPA同样支持多表联查),如果不喜欢使用方法名来定义查询条件或者查询过于复杂的话,@Query标注是一个很不错的选择。
查询结果
我们来写一个Controller展示我们的查询结果:
@RestController
public class TestController {
@Autowired BlogRepository blogRepository;
@RequestMapping(value = "", method=RequestMethod.GET)
public Page<Blog> getEntryByPageable(@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC)
Pageable pageable, @RequestParam(value = "role", defaultValue = "") String role) {
if("".equals(role)){
return blogRepository.findAll(pageable);
}
return blogRepository.findByRole(role, pageable);
}
}
然后,我们进入根目录,运行mvn spring-boot:run
将应用run起来。所有数据会在应用启动时添加进数据库当中。然后我们访问http://localhost:8080/,我们可以得到所有blog的分页结果:
{
"content":[
{
"id":246,
"title":"blog122",
"content":"this is teacher blog content",
"creator":{"id":1,"username":"teacher","role":"teacher"}
},
{
"id":245,
"title":"blog121",
"content":"this is teacher blog content",
"creator":{"id":1,"username":"teacher","role":"teacher"}
},
{
"id":244,
"title":"blog120",
"content":"this is teacher blog content",
"creator":{"id":1,"username":"teacher","role":"teacher"}
},
{
"id":243,
"title":"blog119",
"content":"this is teacher blog content",
"creator":{"id":1,"username":"teacher","role":"teacher"}
},
{
"id":242,
"title":"blog118",
"content":"this is teacher blog content",
"creator":{"id":1,"username":"teacher","role":"teacher"}
}
],
"last":false,
"totalElements":246,
"totalPages":50,"size":5,
"number":0,
"first":true,
"sort":[{"direction":"DESC","property":"id","ignoreCase":false,"nullHandling":"NATIVE","ascending":false}],
"numberOfElements":5
}
接着,再访问http://localhost:8080/?role=student,我们可以得到所有角色为student的用户所创建的blog的分页结果:
{
"content":[
{"id":123,"title":"blog122","content":"this is student blog content","creator":{"id":2,"username":"student","role":"student"}},
{"id":122,"title":"blog121","content":"this is student blog content","creator":{"id":2,"username":"student","role":"student"}},
{"id":121,"title":"blog120","content":"this is student blog content","creator":{"id":2,"username":"student","role":"student"}},
{"id":120,"title":"blog119","content":"this is student blog content","creator":{"id":2,"username":"student","role":"student"}},
{"id":119,"title":"blog118","content":"this is student blog content","creator":{"id":2,"username":"student","role":"student"}}
],
"last":false,
"totalElements":123,
"totalPages":25,
"size":5,
"number":0,
"first":true,
"sort":[{"direction":"DESC","property":"id","ignoreCase":false,"nullHandling":"NATIVE","ascending":false}],
"numberOfElements":5}
版权声明本文由Cliff创作,转载需署名作者且注明文章出处