暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

磐维2.0项目实践

古月方源 2024-04-16
826

1.pw_bulkload

租户进行数据导入,使用pw_bulkload操作时遇到如下两类问题:

  • 提示找不到vbbl这个schema
  • 提示vbbl这个schema没有权限

提示的文本信息如下:

NOTICE: BULK LOAD START
ERROR: query failed: ERROR:  schema "vbbl" does not exist
DETAIL: query was: SELECT * FROM vbbl.pw_bulkload($1)
NOTICE: BULK LOAD START
ERROR: query failed: ERROR:  permission denied for schema vbbl
DETAIL:  N/A
DETAIL: query was: SELECT * FROM vbbl.pw_bulkload($1)

对应的截图如下:

image.png

image.png

pw_bulkload模拟测试

1.首先在db下使用管理员权限账号创建pw_bulkload扩展

CREATE EXTENSION pw_bulkload;

通常连接默认管理库postgres,如果在其他db下使用,也需要在相应的db下执行该操作,否则会出现上面的第1个错误:找不到vbbl这个schema

2.在db下对普通用户赋予vbbl模式的usage权限,使其可调用后续的接口函数

GRANT usage ON SCHEMA vbbl TO admin;

如果不执行该步骤,会出现上面的第2个错误:提示vbbl这个schema没有权限

3.使用pw_bulkload的命令项加载数据
创建测试表

CREATE TABLE test_bulkload(id INT, name VARCHAR);

创建txt文件,写入10个W数据:

$ seq 100000| awk '{print $0"|bulkload"}' > bulkload_output.txt

最后执行如下命令:

$ pw_bulkload \ --input=./bulkload_output.txt \ --output="admin.test_bulkload" \ --option="TYPE=csv" --option="DELIMITER=|" \ --option="ERROR_RECOVERY=YES" \ --port=17700 --dbname=postgres --username=admin --password

注意:
1.连接到哪个db进行操作,就需要在哪个db下创建扩展
2.output参数表名要加模式前缀
3.设置ERROR_RECOVERY=YES,在导入出错时清理本次导入数据。

成功导入的截图如下:
image.png

查看数据:

image.png

4.使用pw_bulkload的控制文件加载数据
可以先清空导入的数据

TRUNCATE TABLE test_bulkload ;

编写.ctl文件

INPUT=/home/panwei/bulkload_output.txt
OUTPUT = admin.test_bulkload
TYPE = CSV
DELIMITER = |
ERROR_RECOVERY=YES

执行命令:

$ pw_bulkload ./my.ctl \ --port=1521 --dbname=postgres --username=admin --password

最后:pw_bulkload插件的设计应该允许指定到public模式更合适。

2.批量插入

使用psql进行数据插入时可使用copy或\copy元命令对数据文件进行批量操作,在JDBC里有两种方式。

方式一:使用reWriteBatchedInserts参数,可将多条insert合并为一条insert,使用insert…values(?),(?)…多values的形式

jdbc:panweidb://ip:port/database_name?reWriteBatchedInserts=true&batchMode=off

注意需要设置batchMode=off,否则会出现如下错误:

batchMode and reWriteBatchedInserts can not both set true!

方式二:使用batchMode=on

jdbc:panweidb://ip:port/database_name?batchMode=on

行存表场景建议使用batchMode=on,插入性能提升更明显。

3.自动保存

psql可使用内置变量ON_ERROR_ROLLBACK,设置为on时允许事务块内的语句遇到错误时,可以被忽略,不回滚整个事务而继续执行。

它的原理是对事务块里的每个语句执行前都创建一个SAVEPOINT保存点,遇到语句执行出错后ROLLBACK到失败语句的保存点,然后继续往下执行。

JDBC里也可以设置autosave参数,功能类似于psql里的ON_ERROR_ROLLBACK。

jdbc:panweidb://ip:port/database_name?autosave=always

使用autosave=always参数进行批量插入时,会创建较多的保存点,可能造成导入较慢,因为保存点未及时清理释放。

注意:从JDBC 42.2.6才开始支持cleanupSavepoints参数,如果使用较低版本的JDBC需要升级一下驱动。

4.B模式下自增主键:auto increment

磐维2.0还支持B模式下auto increment语法,但auto increment语法不支持序列语法方式修改

ALTER LARGE SEQUENCE tab1_id_seq RESTART WITH 1; ERROR: cannot alter sequence owned by auto_increment column

需要使用如下方式修改:

ALTER TABLE tab1 AUTO_INCREMENT = 1;

5.localhost监听问题

创建函数或者存储过程时,提示

error:autonomous transaction failed to create autonomous session

该问题与数据库监听有关,服务端没有配置localhost的监听,在创建存储过程的时候,会创建一个自治事务,这个自治事务的本质上就是服务端自己建立一个目标为localhost的无密码连接,如果localhost无法登录,就会报这个错。

例如监听配置:listen_addresses=“192.168.20.100”

解决方案:配置listen_addresses="*"。

6.数据内容大小写不敏感

PG可以使用citext插件创建citext数据类型,citext数据类型是一个不区分大小写的文本类型,允许在进行文本比较时忽略大小写。

使用场景:citext类型通常用于存储需要忽略大小写的文本数据,如用户名、密码等。通过使用citext数据类型,可以在进行文本比较时更加方便和快速。

在磐维里:PG和A模式下编译citext插件创建citext类型,B模式下对字段设置collate utf8_general_ci即可。
image.png

7.如何使用job

磐维2.0支持A模式下使用DBMS_JOB接口函数使用job

提交job: submit

方式一:

DBMS_JOB.SUBMIT ( in id bigint, in content text, in next_date timestamp without time zone default sysdate, in interval text default 'null', out job integer);

方式二:

DBMS_JOB.SUBMIT ( job OUT BINARY_INTEGER, what IN VARCHAR2, next_date IN DATE DEFAULT sysdate, interval IN VARCHAR2 DEFAULT 'null', no_parse IN BOOLEAN DEFAULT FALSE, instance IN BINARY_INTEGER DEFAULT any_instance, force IN BOOLEAN DEFAULT FALSE);

方式二在传参时使用参数名=>参数值的写法,该用法仅在数据库兼容模式为Oracle时支持

create table t_test(insert_date timestamp); create or replace procedure p_test() as begin insert into t_test values(sysdate); COMMIT; end; / DECLARE JOB_NUM NUMBER; BEGIN DBMS_JOB.SUBMIT(JOB=>JOB_NUM, WHAT => 'p_test;', NEXT_DATE => SYSDATE, INTERVAL => 'TRUNC(SYSDATE,''MI'')+(1)/(24*60)'); COMMIT; END; /

运行job: run

DECLARE JOB_NUM NUMBER; BEGIN SELECT A.JOB INTO JOB_NUM FROM DBA_JOBS A WHERE WHAT = 'p_test;'; dbms_job.run(JOB_NUM); COMMIT; END; /

修改job: change

修改job名称:

DECLARE JOB_NUM NUMBER; BEGIN SELECT A.JOB INTO JOB_NUM FROM DBA_JOBS A WHERE WHAT = 'p_test;'; dbms_job.change(JOB_NUM,'newname;',sysdate,'''1min''::interval'); COMMIT; END; /

查看任务当前执行状

select broken from dba_jobs where what ='newname;';

停止/恢复job: broken

DECLARE JOB_NUM NUMBER; BEGIN SELECT A.JOB INTO JOB_NUM FROM DBA_JOBS A WHERE WHAT = 'newname;'; DBMS_JOB.BROKEN(JOB_NUM,TRUE, SYSDATE); COMMIT; END; /

删除job: remove

select dbms_job.remove(2108);
DECLARE JOB_NUM NUMBER; BEGIN SELECT A.JOB INTO JOB_NUM FROM DBA_JOBS A WHERE WHAT = 'newname;'; dbms_job.remove(JOB_NUM); COMMIT; END; /

与兼容性无关的使用方式:

create table t_sub(insert_date timestamp); select dbms_job.submit(1,'insert into t_sub values(now());',now()::timestamp without time zone,'''1min''::interval'); select dbms_job.run(1); select dbms_job.broken(1,true); select dbms_job.remove(1);

8.Java里的double类型存储到varchar精度丢失问题

数据库表结构如下:

create table t1(a varchar);

Java使用double类型插入数据主要代码如下:

String sql = "insert into t1 values(?)"; PreparedStatement ps = connection.prepareStatement(sql); ps.setObject(1, new Double(48)); ps.execute(); ps.setObject(1, new Double(48.1)); ps.execute(); ps.setObject(1, new Double(48.9)); ps.execute();

应用端应该使用如下几种方式改写:

insert into t1 values(?::numeric)
String.valueOf(new Double(48.1))
new BigDecimal("48.1")

9.存储过程如何返回多个查询结果集

表结构如下:

create table fiverows(id serial primary key,data text); insert into fiverows(data) values('one'),('two'), ('three'),('four'),('five');

存过定义如下

create or replace procedure curtest( out cur1 refcursor,out cur2 refcursor) as begin open cur1 for select id,data from fiverows where id between 1 and 3; open cur2 for select id,data from fiverows where id between 4 and 5; end; /

gsql里测试调用:

postgres=> BEGIN; BEGIN postgres=> CALL curtest(NULL,NULL); cur1 | cur2 --------------------+-------------------- <unnamed portal 1> | <unnamed portal 2> (1 row) postgres=> FETCH ALL "<unnamed portal 1>"; id | data ----+------- 1 | one 2 | two 3 | three (3 rows) postgres=> FETCH ALL "<unnamed portal 2>"; id | data ----+------ 4 | four 5 | five (2 rows)

JAVA测试关键代码如下:

conn.setAutoCommit(false); CallableStatement stmt = null; ResultSet resultSet = null; stmt = conn.prepareCall("{call curtest(?,?)}");; stmt.registerOutParameter(1, Types.REF_CURSOR); stmt.registerOutParameter(2, Types.REF_CURSOR); stmt.execute(); resultSet = (ResultSet) stmt.getObject(1); ... resultSet = (ResultSet) stmt.getObject(2); while(resultSet.next()){ Integer id = (Integer)resultSet.getInt(1); String data = (String) resultSet.getString(2); }
最后修改时间:2024-04-17 15:07:33
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论