利用Mybatis向PostgreSQL中插入并查詢JSON字段
前言:
這里我使用的是TimescaleDB,加了一個(gè)時(shí)間戳字段,不過沒差。關(guān)于PostgreSQL中Json數(shù)據(jù)類型的操作,可以參考官網(wǎng)。
應(yīng)用場(chǎng)景介紹
將TCP發(fā)過來的數(shù)據(jù)包(通過消息隊(duì)列發(fā)過來)解析出數(shù)據(jù)(一個(gè)數(shù)據(jù)包含有多幀,一幀中含有多條信息),并和本地規(guī)則表的格式對(duì)應(yīng)起來。以JsonLineMsg實(shí)體類代表對(duì)應(yīng)的一幀數(shù)據(jù):
package tsdb.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.sql.Timestamp;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class JsonLineMsg {
private Timestamp timeStamp; // 時(shí)間戳
private String keyAndRuleData; // key value,key為根據(jù)規(guī)則表生成的唯一標(biāo)識(shí),value為TCP解析出的對(duì)應(yīng)的數(shù)據(jù)。這個(gè)字段對(duì)應(yīng)數(shù)據(jù)庫中的Json類型字段,String類型進(jìn)入數(shù)據(jù)庫還需轉(zhuǎn)換為Json格式。
}對(duì)應(yīng)psql的表結(jié)構(gòu)為:

上面JsonLineMsg實(shí)體類的一個(gè)對(duì)象就代表的一幀中的所有數(shù)據(jù)項(xiàng)many(key:value),keyAndRuleData字段用來存儲(chǔ)所有數(shù)據(jù)項(xiàng),在psql中對(duì)應(yīng)一個(gè)類型為json(或jsonb)的字段。
數(shù)據(jù)insert
為了查詢JSON中的字段,在insert的過程中有些注意事項(xiàng),如果插入時(shí)JSON格式不正確,查詢JSON字段是總返回null。
記錄一下:為了降低數(shù)據(jù)庫打開關(guān)閉的耗時(shí),每積累20幀持久化一次。
note:
- foreach批量插入 、 mybatis ExecutorType.BATCH模式插入 、 for循環(huán)insert
- 其實(shí)實(shí)際意義上來說,包括在程序里面for循環(huán)還是在sql里面for循環(huán)都不算是批量操作。只有將ExecutorType設(shè)置為BATCH模式才是真正意義上的批量操作。 并且事實(shí)證明在sql循環(huán)時(shí)設(shè)置batch與否其實(shí)執(zhí)行時(shí)間差別不是很大,幾乎可以忽略不計(jì)。所以其實(shí)如果不是特別要求性能??梢灾苯釉趕ql中使用for循環(huán)即可 。謹(jǐn)慎使用batch,如果需要使用batch,請(qǐng)?jiān)谛枰暮瘮?shù)上面設(shè)置batch,不要全局使用。因?yàn)閎atch也是有副作用的。 比如在Insert操作時(shí),在事務(wù)沒有提交之前,是沒有辦法獲取到自增的id,;此外,對(duì)于update、delete無法返回更新、插入條數(shù)。這在某型情形下是不符合業(yè)務(wù)要求的。上面的是搬運(yùn)的,不過后來有看了看,還是應(yīng)該用BATCH的Executor來批量導(dǎo)入,實(shí)際項(xiàng)目中foreach不可控,指不定啥時(shí)候就報(bào)錯(cuò)了,文章最后記錄了ExecutorType為BATCH寫法的關(guān)鍵部分) foreach的xml拼接sql是最不推薦的方式,使用時(shí)有大段的xml和sql語句要寫,很容易出錯(cuò),工作效率很低。更關(guān)鍵點(diǎn)是,雖然效率尚可,但是真正需要效率的時(shí)候你掛了,要你何用? 批處理執(zhí)行是有大數(shù)據(jù)量插入時(shí)推薦的做法,使用起來也比較方便。
- 關(guān)于批處理的方式的具體說明,可以參考推文強(qiáng)烈推薦MyBatis 三種批量插入方式的比較或者去StackOverFlow查一下,講解的比較全面,總之,還是用ExecutorType為BATCH寫法比較靠譜。
一幀中包含多條信息,一條信息對(duì)應(yīng)一個(gè)key:value,所以每次從規(guī)則表生成的key和TCP解析出的value都要加到一個(gè)代表一幀所有數(shù)據(jù)的JSON串中。
要注意的代碼如下:
// 存儲(chǔ)一幀的所有key:value
StringBuilder json = new StringBuilder();
json.append("{");
// frmLen 幀中信息個(gè)數(shù)
for (int j = 0; j < frmLen; j++) {
StatRule stat = frm.getStat(j);
assert stat != null;
// 一條stat的key和value
int key = stat.getKey();
long value = System.nanoTime();
// String value = ParseStat.Parse(datas, stat);
json.append("\""); // key左右必須加引號(hào),key必為String類型
json.append(key);
json.append("\"");
json.append(":");
// json.append("\"");
json.append(value); // value左右不是必須加引號(hào),若是String則加
// json.append("\"");
if ((j != statLen - 1)) {
json.append(",");
}
}
json.append("}");
JsonLineMsg jsonLineMsg = new JsonLineMsg(new Timestamp(System.currentTimeMillis()), json.toString());要注意的就是這個(gè)key和value加入數(shù)據(jù)庫的類型如果為text(即java字符串)就要加引號(hào),所以key兩頭必須加,value看情況。
對(duì)應(yīng)的XML中的語句:
<insert id="batchInsertJsonLineMsg"
useGeneratedKeys="true" >
insert into jsonlinemsg (timestamp ,keyandruledata ) values
<foreach item="item" collection="list" separator="," close=";">
(#{item.timeStamp},(#{item.keyAndRuleData})::json)
</foreach>
</insert>這個(gè)::json就是將非json類型轉(zhuǎn)為json類型,否則JAVA中String類型會(huì)對(duì)應(yīng)其他的數(shù)據(jù)庫字段類型,插入會(huì)報(bào)錯(cuò)。
note: psql 4種類型轉(zhuǎn)換 https://www.postgresql.org/docs/14/sql-syntax-lexical.html
type 'string'只能用于字面常量轉(zhuǎn)換、且不能用于數(shù)組中typename ( 'string' )可用于運(yùn)行時(shí)類型轉(zhuǎn)換'string'::type可用于數(shù)組,可用于運(yùn)行時(shí)類型轉(zhuǎn)換CAST ( 'string' AS type )可用于數(shù)組,可用于運(yùn)行時(shí)類型轉(zhuǎn)換
插入后用Navicat查看:

如果查看到類似于 "{"1":"1_234"}"、{\"1\":\"1_123\"}這樣,格式就是不正確的,查詢JSON中字段會(huì)返回null。
數(shù)據(jù)select
<select id="selectValueData" resultType="String">
select keyandruledata::json ->>#{key} from jsonlinemsg where timestamp = (#{time}::timestamp)
</select>要注意的就是這個(gè)::json,至于 -> 還是 ->>可以參考開頭的官網(wǎng)鏈接。
ps: timescaledb官網(wǎng)推薦用jsonb,但是我測(cè)試發(fā)現(xiàn)jsonb查詢插入都比不上json,不知道為啥
ps: 發(fā)現(xiàn)了,原來是轉(zhuǎn)換為tsdb時(shí),索引沒建立起來,重新建表又測(cè)試了一遍,確實(shí)jsonb讀取快。
BATCH 批量插入
// 獲取連接的方法,設(shè)置ExecutorType.BATCH以及關(guān)閉自動(dòng)提交
public static SqlSession getSessionForBatch(String xmlPath, Properties properties) throws IOException {
return MybatisUtil.getSqlSessionFactory(xmlPath, properties).openSession(ExecutorType.BATCH,false);
} public void update(List<PropUrl> propUrlLst) throws IOException {
// ExecutorType.BATCH
try (SqlSession session = MybatisUtil.getSessionForBatch(myBatisConfigXmlPath)) {
InitTsdbUrlTableMapper mapper = (InitTsdbUrlTableMapper) session.getMapper(mapperClazz);
for (int i = 0; i < propUrlLst.size(); i++) {
mapper.updatePropMatchRule(propUrlLst.get(i));
// 每50次提交一次防止內(nèi)存溢出
if ((i+1) % 50 == 0) {
session.commit();
session.clearCache();
}
}
session.commit();
session.clearCache();
log.info("update successfully ->{}", propUrlLst);
}
}到此這篇關(guān)于利用Mybatis向PostgreSQL中插入并查詢JSON字段的文章就介紹到這了,更多相關(guān)Mybatis查詢JSON字段內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot Admin使用及心跳檢測(cè)原理分析
這篇文章主要介紹了SpringBoot Admin使用及心跳檢測(cè)原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java為何需要平衡方法調(diào)用與內(nèi)聯(lián)
這篇文章主要介紹了Java為何需要平衡方法調(diào)用與內(nèi)聯(lián),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01
Java實(shí)現(xiàn)的AES256加密解密功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的AES256加密解密功能,結(jié)合完整實(shí)例形式分析了Java實(shí)現(xiàn)AES256加密解密功能的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02
Springboot實(shí)現(xiàn)多服務(wù)器session共享
這篇文章主要為大家詳細(xì)介紹了Springboot實(shí)現(xiàn)多服務(wù)器session共享,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
詳解Java利用同步塊synchronized()保證并發(fā)安全
這篇文章主要介紹了Java利用同步塊synchronized()保證并發(fā)安全,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03

