使用PostgreSQL保存二进制的Protobuf

莱莱  金牌会员 | 2023-2-12 14:36:41 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 676|帖子 676|积分 2028

前言

PostgreSQL 可以直接存储二进制字段,而上周我学习了通过Protobuf来做grpc通信格式,当然也是可以序列化为二进制存入数据库的,需要的时候从数据库查询出来,通过protobuf来转成对应的Java对象,本文就是来尝试一下这个思路。
PostgreSQL 安装

使用docker来安装PostgreSQL, 参照网站https://hub.docker.com/_/postgres
命令如下
docker run --name my-postgres -p 5432:5432  -e POSTGRES_PASSWORD=kentest123$# -d postgres
以上命令会去下载postgresql的image,并运行起来, 如果需要我们程序访问,-p一定要加上,把端口打开,不然程序不能连过去。
docker启动后,可以使用如下命令,同时sh来查看数据库资源
docker exec -it my-postgres sh
再执行psql可以输入select语句
psql -U postgres
\l 是显示所有数据库
\c 数据库名;  切换到某个数据库,我们使用用户postgres,默认会进入名为postgre的数据库
\d 是查看数据库中所有表
\d 表名是查看表的定义。
查看表的大小
select pg_size_pretty(pg_relation_size('customer')) as size;
代码编写

这里直接用JPA来完成数据对数据库的访问
定义一个实体
  1. @Entity
  2. @Table(name = "market_price_byte")
  3. @Data
  4. @Builder
  5. @NoArgsConstructor
  6. @AllArgsConstructor
  7. public class MarketPriceByte implements Serializable {
  8.     @Id
  9.     private String id;
  10.     @Column(name = "values", nullable = false)
  11.     private byte[] values;
  12. }
复制代码
MarketPriceByte 对应数据库market_price_byte, 两个字段一个是id, 一个是byte数组,后面用来存我们的protobuf。
定义protobuf文件

定义一个proto文件pricevalue.proto
  1. syntax = "proto3";
  2. option java_multiple_files = true;
  3. option java_package = "ken.postgresql.proto";
  4. option java_outer_classname = "PriceValueProto";
  5. option objc_class_prefix = "HLW";
  6. package proto;
  7. message PriceValue {
  8.   sint32 date = 1;
  9.   double open = 2;
  10.   double high = 3;
  11.   double low = 4;
  12.   double close = 5;
  13. }
  14. message PriceValues {
  15.   repeated PriceValue price_value = 1;
  16. }
复制代码
PriceValue表示一天的股票价格,  PriceValues是历史价格,我们就是把它序列化后存入到ProgresSQL里面。
使用上篇用到的maven插件生成对应的Java类
编写代码

首先我们定义一个JpaRepository用来存取数据库记录
public interface MarketPriceByteRepository extends JpaRepository {
}
在配置文件中设置数据库配置
  1. spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
  2. spring.datasource.username=postgres
  3. spring.datasource.password=kentest123$#
  4. spring.jpa.hibernate.ddl-auto=update
  5. spring.jpa.properties.hibernate.show_sql=true
  6. spring.jpa.properties.hibernate.format_sql=true
复制代码
spring.jpa.hibernate.ddl-auto 设置成 update,是代码有更新的时候,同步更新数据库表
编写一个Service用来存数据到数据库和从数据库取数据
  1. @Service
  2. @Slf4j
  3. public class MarketPriceService {
  4.     @Autowired
  5.     private MarketPriceByteRepository repository;
  6.     public void createMarketPrice() {
  7.         MarketPriceByte newMarketPrice = new MarketPriceByte();
  8.         newMarketPrice.setId("0000000001");
  9.         PriceValue priceValue = PriceValue.newBuilder()
  10.                 .setDate(100)
  11.                 .setOpen(1.01)
  12.                 .setHigh(1.12)
  13.                 .setLow(1.00)
  14.                 .setClose(1.11).build();
  15.         PriceValue priceValue2 = PriceValue.newBuilder()
  16.                 .setDate(101)
  17.                 .setOpen(2.01)
  18.                 .setHigh(2.12)
  19.                 .setLow(2.00)
  20.                 .setClose(2.11).build();
  21.         PriceValues priceValues = PriceValues.newBuilder()
  22.                 .addPriceValue(priceValue)
  23.                 .addPriceValue(priceValue2)
  24.                 .build();
  25.         newMarketPrice.setValues(priceValues.toByteArray());
  26.         log.info("Saving new MarketPrice...");
  27.         this.repository.save(newMarketPrice);
  28.     }
  29.     public void queryAllMarketPrices() {
  30.         List<MarketPriceByte> allMarketPrices = this.repository.findAll();
  31.         log.info("Number of MarketPrices: " + allMarketPrices.size());
  32.         if(allMarketPrices.size() > 0)
  33.         {
  34.             MarketPriceByte marketPriceByte = allMarketPrices.get(0);
  35.             log.info(marketPriceByte.getId());
  36.             byte[] values = marketPriceByte.getValues();
  37.             try {
  38.                 PriceValues priceValues =  PriceValues.parseFrom(values);
  39.                 PriceValue priceValue1 = priceValues.getPriceValue(0);
  40.                 PriceValue priceValue2 = priceValues.getPriceValue(1);
  41.                 log.info(priceValue1.toString());
  42.                 log.info(priceValue2.toString());
  43.             } catch (InvalidProtocolBufferException e) {
  44.                 throw new RuntimeException(e);
  45.             }
  46.         }
  47.     }
  48. }
复制代码
createMarketPrice 我们hardcode了一个MarketPriceByte对象,Java对象序列化为protobuf
priceValues.toByteArray()
然后通过MarketPriceByteRepository存入数据库
queryAllMarketPrices 将我们存入的数据查询出来,完成从byte[] 转成 Java对象 “PriceValues.parseFrom(values)”
调用代码:
marketPriceService.createMarketPrice();
marketPriceService.queryAllMarketPrices();
调用后,我们到数据库查询,可以看到我们hardcode的那条记录

这样就完成了把protobuf对象存入到progresql数据库。
总结

上面的代码比较简单,但对于第一次接触的同学还是有些工作在这里面, 比如docker里面运行postgresql, JPA是否支持postgresql定义的二进制字段, Protobuf生成的对象怎么转成byte[]
这些东西虽然简单,但是也只有自己动手写一写,才印象比较深刻,才更好的理解。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莱莱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表