Closed cbqqkcel closed 12 months ago
id是没有空字符串的。
根据ID却查询不到数据
这个是刚更新完seq bug 后压力测试下插入的数据。之前是没有这个问题的。
你的 insert 语句是什么样子? id 是 varchar,跟 sequence 没有关系。
也可能是昨天提交的代码,我只是跑通了所有单元测试,性能测试还没有做。
INSERT INTO `PurchaseInBill`(`id`, `orderId`, `supplierId`, `supplier`, `warehouseId`, `status`, `tenantId`, `totalQty`,
`totalAmount`, `version`, `createAt`, `updateAt`)
VALUES ('POIS100784', 'PO0101300', 1, '默认', 1, 1, 0, 4300.0000000000, 860000.00000000000000000000, 0, now(), now())
@Override
public boolean create(PurchaseInBill header) {
header.setId("POIS" + nextId());
header.setStatus(InBillStatus.CREATE);
if (header.getWarehouseId() == null) {
header.setWarehouseId(WarehouseUtil.picker().getId());
}
$.setTotal(header);
super.create(header);
return lineService.create(header.getLines());
}
create是加了事务的方法
nextId()
public class IdUtil {
public static Long getSequenceId(Class<?> clazz) {
var row = Db.selectOneBySql(StrUtil.format("select {}.NEXTVAL as value", clazz.getSimpleName()));
return row.getLong("value");
}
}
是不是索引坏了。查询比较慢的时候我重启服务了。
这个问题也比较奇葩
create sequence if not exists PurchaseInBillLine;
create table if not exists PurchaseInBillLine
(
id bigint default (NEXT VALUE FOR PurchaseInBillLine) primary key,
headerId varchar not null,
remark varchar,
skuId bigint not null,
qty bigint not null,
price bigint,
areaId integer,
locationId integer,
batchNo varchar(32),
tenantId integer not null default 0,
createAt timestamp,
updateAt timestamp,
isDelete boolean not null default false,
foreign key (headerId) references PurchaseInBill (id) on delete cascade
);
这个我主键是不为空,自动生成的。这么能查询出Id为空的数据出来了
你把历史数据清一下再重新跑跑,昨天提交的代码修复了一些问题。
我现在压测下面的代码:
private void executeInNewThread(CountDownLatch latch) {
new Thread(() -> {
try {
Connection conn = getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate("set lock_timeout 1000000");
conn.setAutoCommit(false);
for (int row = 0; row < 1000; row++) {
ResultSet rs = stmt.executeQuery("SELECT seq_locked.NEXTVAL");
rs.next();
int v = rs.getInt(1);
rs.close();
stmt.execute(
"insert into SequenceLockedExceptionTest values('f" + v + "', " + row + ")");
conn.commit();
}
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
发现一个问题是压测久了变慢,数据是能查的。
通过 create sequence 创建的 sequence,是共享 sequence,是严格支持单调递增的,如果多个事务并发执行 sequence.NEXTVAL,实际上是串行执行,也就是即便事务回滚了,sequence 也会自动回滚到上一个值。
共享 sequence 比较慢,如果只是为了得到一个自增的主键,在建表时使用 id long auto_increment primary key 会快很多。
测试了一下暂时没有问题 我这个主表ID是字符串要加前缀的POSI的
id long auto_increment primary key, 创建的能指定seq名称,和起始值吗 不能指定名称好像就不好在创建表的时候设置起始值,要查询一下才自动SEQ名称是啥然后修改
共享的能指定不回滚到上一个值吗
测试了一下暂时没有问题 我这个主表ID是字符串要加前缀的POSI的
一般的ID都有生成策略的,如果能在SEQ指定策略就方便多了。 比如 前缀+日期+自增+后缀啥的。 不够这个需求很难通用。一般的项目都是自己键一张表维护ID。
auto_increment 目前没有其他配置项。 共享 sequence 不能指定不回滚。
如果主键是字符串,想用 sequence 来组装,你可以直接在 insert 语句里面这样写: insert into test(pk) values('POSI'||seq.NEXTVAL), 不用在一个事务里用另一条 select 语句查出 sequence 的值,这样也很快。
这样就要写 SQL语句插入了,一般的框架都封装好了insert方法,回头看看框架支持不。否则为了这点性能写SQL又太麻烦了
正常来讲即便串行执行也满足大多数中小企业的需求的,我现在压测久了变慢,可能哪里还是有点问题,比如 GC,最开始也是很快的。
通过 create sequence 语句来关联某个表,让它变成某个表的私有 sequence 是很容易做到的,我改进一下。 通过 auto_increment 创建的 sequence 就是带有 BELONGS_TO_TABLE 关键字的。
findByHeaderId = select * from PurchaseOrderLine where headerId = 'PO0101419'
这个是还未提交事务。
这个过程如下
insert header = PurchaseOrder
insert lines = PurchaseOrderLines
查询 lines 然后出现了qty为空的情况。数据库的创建语句设置了 qty 不为空的。
也是在压力测试下出现的问题。
不知道是数据库的问题还框架的问题。
我记错了 auto_increment 后面支持 start 和 increment, 语法像这样 id long auto_increment(1000) 或 id long auto_increment(1000,1)
43条数据,出错的时候总是有一条空数据
可能还是数据库的问题,昨天的改动很核心,正在跑 tpcc,也遇到一些问题。
又出现了,这次不是多线程出现的,昨天好好的,今天可能是重启比较多然后就出现了。今天没有新增数据。
是正常停止数据库还是直接杀死?如果没有新增数据按道理不会有修改操作了,最多就是重启时执行一下老的 redo log。正常停止数据库会自动执行一次 checkpoint,重启时也不会有 redo log。
大部分情况是正常重启的。主要25日-27日的数据都有问题。就几条
我刚才测试了一下新增了一条数据后,然后正常停止 会打印 Stopping TcpServer accepter TcpServer stopped 之后再启动数据就这样了
不重启就不会有问题,哪怕我在重启之前执行 backup to "xxx.zip" 然后正常重启,还是会出现问题。
redo_log有许多文件
感觉触发了一个特点的BUG开关,现在100%出现这个问题。之前还是多线程情况下才会有的。
我马上排查一下问题
redo_log有许多文件
这个是已经归档的 redo log,会自动删除的,上一级目录的 redo log 才有用。
我前几天改了一下 gc 算法,现在压测也每次都出问题,可能改出 bug 了。