本期问答如下:
- "ERROR: tuple concurrently updated/deleted"报错
- timestamp时间类型秒精度显示问题
Q1."ERROR: tuple concurrently updated/deleted"报错
在pg群里看到这个问题:给用户加权限的时候报tuple concurrently updated的错误,同时发现有一个长连接对加权限的表执行drop操作。
在本地环境模拟该错误,session 1执行如下操作:
create table t();
begin;
drop table t;
session 1模拟长连接对drop操作,接着session 2执行grant操作:
grant select on t to postgres;
此时session 2会产生锁等待,直到session 1提交。
session 1发起commit语句提交后,session 2就会出现报错:
我本地测试的pg版本是15,提示的错误信息是"tuple concurrently deleted",与"tuple concurrently updated"信息类似,推测pg不同大版本对该错误信息提示有优化。
使用低版本继续进行复现,可以发现从pg 12版本开始,该场景的提示信息为"tuple concurrently deleted",pg 12之前的版本提示信息为"tuple concurrently updated"
DCL语句赋权时,与事物级DDL语句产生冲突,不同的pg版本会提示"ERROR: tuple concurrently updated"或"ERROR: tuple concurrently deleted"的报错信息。
Q2.timestamp时间类型秒精度显示问题
问题描述
jdbc接口对timestamp类型使用java.sql.timestamp类型接收后,再进行字符串格式化时尾部会显示多余0。
使用如下代码可以观察,按照jdbc实现标准,java.sql.timestamp类型格式化后会显示秒的精度值,即便值为0也会显示,而使用String类型接收则会自动去掉0。
问题解答
在oracle迁移场景会使用timestamp(0)来代替oracle的date类型,因为pg的date类型是纯的日期,不存储时间。
客户实际场景使用数据库持久化框架hibernate的SQLQuery接口进行List查询后,timestamp(0)类型字段值尾部显示无意义的0。
应用程序其实只需要按照oracle兼容性显示日期,不需要显示时间,在hibernate里可以通过继承数据库方言并重写接口的形式来集中化处理这个问题。
重写的方言类如下:
public class MyDialect extends PostgreSQLDialect {
public MyDialect() {
super();
}
public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException {
if (code == Types.TIMESTAMP) {
if (scale == 0) {
return org.hibernate.Hibernate.DATE.getName();
}
}
return super.getHibernateTypeName(code,length,precision,scale);
}
}
然后修改hibernate配置文件
<property name="dialect">x.x.x.MyDialect</property>
最后再使用hibernate的SQLQuery接口进行测试,从下面的测试截图可以看到符合预期。