12 DB操作 Hibernate Panache

很久没有更新了,最近实在是太忙了也有其它的学习计划, 目前同步学习的有Spring的WebFlux和Vertx,工作上还被要求学Clujure。其实对于Quarkus的学习很简单,官网教程写的很清楚使用起来也非常简单。我也是按官网文档来写的,算是提前蹚一下坑吧目前来看文档写的还是很规范的。不过由于Quarkus更新太快了,有些功能或者组件或者组件在版本之间可能会有坑,我们项目上已经出现了= =。好了继承上一篇Hibernate的基本使用教程,本讲主要是Hibernate更高级的封装版本,当然也更加好用了。

1. 搭建项目

引入依赖:

    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-orm-panache</artifactId>
        </dependency>

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-postgresql</artifactId>
        </dependency>

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-jackson</artifactId>
        </dependency>
    </dependencies>

依赖也很简单,quarkus-hibernate-orm-panache是我们本章要用的Api,quarkus-jdbc-postgresql Postgresql连接,quarkus-resteasy-jackson 提供Rest服务。

配置项目

只需要配置一下数据源和Hibernate就行了,同时Panache也支持多数据源的配置,所以我这就直接使用多数据源的方案来做Demo,后面不在单独讲。

# user 数据源
quarkus.datasource.user.db-kind=postgresql
quarkus.datasource.user.jdbc.url=jdbc:postgresql://192.168.199.125:5432/quarkus_demo
quarkus.datasource.user.username=postgres
quarkus.datasource.user.password=postgres
# User数据源的 Hibernate 配置
quarkus.hibernate-orm.user.log.sql=true
quarkus.hibernate-orm.user.log.format-sql=false
quarkus.hibernate-orm.user.database.generation=none
quarkus.hibernate-orm.user.packages=com.quarkus.entity.users
quarkus.hibernate-orm.user.datasource=user # 这里指定要使用的数据源
#  UserDes 数据源配置
quarkus.datasource.des.db-kind=postgresql
quarkus.datasource.des.jdbc.url=jdbc:postgresql://192.168.199.125:5432/quarkus_demo
quarkus.datasource.des.username=postgres
quarkus.datasource.des.password=postgres
# UserDes的Hibernate配置
quarkus.hibernate-orm.des.log.sql=true
quarkus.hibernate-orm.des.log.format-sql=false
quarkus.hibernate-orm.des.database.generation=none
quarkus.hibernate-orm.des.packages=com.quarkus.entity.des
quarkus.hibernate-orm.des.datasource=des  # 这里指定要使用的数据源

事实上 Hibernate orm panache 提供了更加高级的API,简化Hibernate开发,它提供了两种编程方式:

  • 使用Entity进行开发,我们的Entity通过继承PanacheEntity实现。
  • 使用Repository开发, 新增一个Repository类实现PanacheRepository接口。

2. Entity开发模式

这个方案有点类似Django的感觉,通过继承PanacheEntity使用封装好的各种API,开发起来既简单有方便。

2.1 配置Entity

@Entity(name = "t_user")
public class User extends PanacheEntity {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

可以看到我们的Entity中并没有定义主键,实际上它默认在PanacheEntity定义了,默认主键字段为Long id 。数据库表设计也非常简单:

2.2 实现一个简单的CRUD

在这里插入图片描述
实际上User从Panache继承了大量的操作数据库的方法,我们就可以使用这个方法来进行编程,不在需要使用EntityManager那种原始方式。

@Path("user")
public class UserResource {


    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getUserById(@PathParam("id") Long id){
        return User.findById(id);
    }


    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Transactional
    public int save(User user){
        user.persist();
        return 1;
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional
    public User update(User user){

        User u = User.findById(user.id);

        u.setName(user.getName());

        return user;
    }


    @DELETE
    @Transactional
    @Path("{id}")
    public boolean delete(@PathParam("id") Long id){

        return User.deleteById(id);
    }

}

注意,增删改不要忘了加@Transactional注解哦,否则会报错的

2.3 其它常用的API:

// creating a person
Person person = new Person();
person.name = "Stef";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// 持久化操作
person.persist();

// 判断是否持久化
if(person.isPersistent()){
    // 删除操作  
    // 注意: 删除 修改这类的操作只能是持久化状态的对象才能操作
    person.delete();
}

// 查询列表
List<Person> allPersons = Person.listAll();

// 根据Id查询
person = Person.findById(personId);

// 根据ID查询获取的是Optional包裹的对象
Optional<Person> optional = Person.findByIdOptional(personId);
person = optional.orElseThrow(() -> new NotFoundException());

// 简单条件查询
List<Person> livingPersons = Person.list("status", Status.Alive);

// 计数
long countAll = Person.count();

// 根据条件计数
long countAlive = Person.count("status", Status.Alive);

// 根据条件删除
Person.delete("status", Status.Alive);

// 删除所有
Person.deleteAll();

// 根据ID删除
boolean deleted = Person.deleteById(personId);

// 条件更新
Person.update("name = 'Mortal' where status = ?1", Status.Alive);

3. Repository 开发模式

3.1 配置Entity

这种模式的Entity跟Jpa的配置是一样的,不需要其它特殊的配置。

@Entity(name = "user_des")
public class UserDes {

    @Id
    @SequenceGenerator(name = "user_des_id_seq", sequenceName = "user_des_id_seq", initialValue = 1, allocationSize = 1)
    @GeneratedValue(generator = "user_des_id_seq")
    private Integer id;

    private String name;

    private String des;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }
}

3.2 创建Repository

@ApplicationScoped
public class UserDesRepository implements PanacheRepository<UserDes> {

}

这里并没有任何实现的方法,实际上我们实现了PanacheRepository后就继承了Hibernate的所有操作,跟PanacheEntity 类似。

3.3 实现CRUD

@Path("des")
public class UserDesResource {

    @Inject
    UserDesRepository userDesRepository;


    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public UserDes get(@PathParam("id") Long id){
        return userDesRepository.findById(id);
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional
    public UserDes save(UserDes userDes){
        userDesRepository.persist(userDes);
        return userDes;
    }

    @DELETE
    @Path("{id}")
    @Transactional
    public boolean delete(@PathParam("id") Long id){
        return userDesRepository.deleteById(id);
    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional
    public UserDes updateById(UserDes userDes){
        UserDes des = userDesRepository.findById(userDes.getId().longValue());
        des.setDes(userDes.getDes());
        des.setName(userDes.getName());
        return des;
    }
}

对于其它的API 跟 PanacheEntity提供的基本一致不再赘述。

4 高级查询

4.1 分页查询

You should only use list and stream methods if your table contains small enough data sets. For larger data sets you can use the find method equivalents, which return a PanacheQuery on which you can do paging。

官网有这么一句话,就是说如果有少量数据可以使用list()方法获取所有,如果数据量过大应该先使用findxxx先获取PanacheQuery 对象 然后设置 page() 进行分页查询。
示例:

    @GET
    @Path("queryByPage")
    @Produces(MediaType.APPLICATION_JSON)
    public JsonObject queryByPage(@QueryParam("name") String name, @QueryParam("pageSize") Integer pageSize, @QueryParam("pageNum") Integer pageNum){
        PanacheQuery<User> query = User.find("name", Sort.ascending("id"), name);

        query.page(Page.of(pageNum, pageSize));


        JsonObject res = new JsonObject();

        res.put("code", 200);
        res.put("data", query.list());
        // 总页数
        res.put("pages", query.pageCount());
        // 总记录数
        res.put("total", query.count());

        return res;
    }

需要注意的是Page.of(index,size) 这里的index 只的就是页码而且是从0开始的。

4.2 排序

其实上面分页的代码里就已经使用了分页,想分页、排序这种功能都是单独封装的一个类Sort
简单使用:

List<Person> persons = Person.list(Sort.by("name").and("birth"));
List<Person> persons = Person.list("status", Sort.by("name").and("birth"), Status.Alive);
// 如果要指定排序规则
Sort.ascending("id")

4.3 简单查询数据

其实在上面我们已经使用过了如Person.list("status",1) 这是一种简单的方式,Panache默认支持下面几种:

  • from EntityName [where …​] [order by …​]
  • order by ... 相当于 from EntityName order by …​
  • <singleColumnName> 相当于 from EntityName where <singleColumnName> = ?
  • <query> 相当于 from EntityName where <query>

更新操作也支持类似的语法:

  • from EntityName …​ 相当于 update from EntityName …​
  • set? <singleColumnName> 相当于 update from EntityName set <singleColumnName> = ?
  • set? <update-query>相当于 update from EntityName set <update-query>
    示例:
    @PUT
    @Path("updateByQuery")
    @Transactional
    public int updateByQuery(@QueryParam("name") String name, @QueryParam("newName") String newName){
        return User.update("set name = ?1 where name like ?2", newName, String.format("%%%s%%", name));
    }

也可以直接写完整的SQL:

    @PUT
    @Path("updateByQuery")
    @Transactional
    public int updateByQuery(@QueryParam("name") String name, @QueryParam("newName") String newName){
        return User.update("update t_user set name = ?1 where name like ?2", newName, String.format("%%%s%%", name));
    }

4.4 预定义查询

对于一些常用的查询HQL可以预定义,在使用的时候通过#来调用即可:

@Entity
@NamedQuery(name = "Person.getByName", query = "from Person where name = :name")
public class Person extends PanacheEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    public static Person findByName(String name){
        return find("#Person.getByName", name).firstResult();
    }
}

只支持Entity编程模式。

4.5 参数匹配

  • 第一种方式。当我们使用HQL查询时,语句"name = ?1 and status = ?2 ?x代表的就是一个参数,如使用list()方法时,就可以直接在后面跟上参数即可Person.find("name = ?1 and status = ?2", "stef", Status.Alive);。参数的位置不能变。
  • 第二种方式。使用Map传递参数,需要指明参数名称。
Map<String, Object> params = new HashMap<>();
params.put("name", "stef");
params.put("status", Status.Alive);
Person.find("name = :name and status = :status", params);

总结

本章主要讲了Hibernate Panache的使用,它提供了更加简单和高级的Hibernate开发方式,使用起来更加方便和快捷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值