You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot无法创建Session:PRIMARY_ID插入空值异常求助

解决Spring Session插入时PRIMARY_ID字段NULL值异常

嘿,我看你碰到了Spring Session插入会话数据时的主键NULL问题,这事儿我之前也遇到过——你的SPRING_SESSION表把PRIMARY_ID设成了非空主键,但Spring Session默认的插入SQL根本没包含这个字段,数据库当然会报错啦。

问题出在哪?

你自定义的表结构用了PRIMARY_ID作为主键,但Spring Session的JDBC存储默认只处理SESSION_IDCREATION_TIME这些标准字段,完全不知道要给PRIMARY_ID赋值,所以插入时这个字段就是NULL,直接触发了数据库的非空约束。

怎么解决?

给你两个实用的方案,选哪个看你需求:

1. 让Spring Session适配你的表结构

如果想保留现有的表结构,就得告诉Spring Session要处理PRIMARY_ID字段。

Spring Boot环境下用属性配置最方便
application.properties里加这些配置,自定义插入SQL并生成主键:

# 指定会话表名
spring.session.jdbc.table-name=SPRING_SESSION
# 禁止自动生成表结构(避免覆盖你的自定义表)
spring.session.jdbc.initialize-schema=never
# 自定义插入SQL,用UUID生成PRIMARY_ID(根据你的数据库换对应函数,比如SQL Server用NEWID())
spring.session.jdbc.insert-session-sql=INSERT INTO SPRING_SESSION (PRIMARY_ID, SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, EXPIRY_TIME, PRINCIPAL_NAME) VALUES (UUID(), ?, ?, ?, ?, ?, ?)

如果是非Spring Boot场景,就自定义SessionRepository
写个继承自JdbcOperationsSessionRepository的子类,重写插入方法手动赋值PRIMARY_ID

@Repository
public class CustomJdbcSessionRepository extends JdbcOperationsSessionRepository {

    public CustomJdbcSessionRepository(JdbcOperations jdbcOperations, PlatformTransactionManager transactionManager) {
        super(jdbcOperations, transactionManager);
        setTableName("SPRING_SESSION");
    }

    @Override
    protected void insertSession(Session session) {
        // 生成主键ID
        String primaryId = UUID.randomUUID().toString();
        getJdbcOperations().update(
            "INSERT INTO SPRING_SESSION (PRIMARY_ID, SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, EXPIRY_TIME, PRINCIPAL_NAME) VALUES (?, ?, ?, ?, ?, ?, ?)",
            primaryId,
            session.getId(),
            session.getCreationTime(),
            session.getLastAccessedTime(),
            session.getMaxInactiveInterval().getSeconds(),
            session.getCreationTime() + session.getMaxInactiveInterval().toMillis(),
            session.getPrincipalName()
        );
    }
}

然后在配置类里把这个自定义的Repository注册成Bean,替换默认的实现就行。

2. 修改表结构适配Spring Session默认逻辑

要是不想改代码配置,那就调整表结构,把SESSION_ID设为主键(这也是Spring Session默认的表设计):

-- 先删除原主键
ALTER TABLE SPRING_SESSION DROP PRIMARY KEY;
-- 把SESSION_ID设为主键
ALTER TABLE SPRING_SESSION ADD CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID);
-- 删除原来的SESSION_ID唯一索引(因为主键已经唯一了)
DROP INDEX SPRING_SESSION_IX1 ON SPRING_SESSION;
-- 更新关联表的外键,指向新的主键
ALTER TABLE SPRING_SESSION_ATTRIBUTES DROP CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK;
ALTER TABLE SPRING_SESSION_ATTRIBUTES ADD CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE;
-- 要是不用PRIMARY_ID了,就删掉它
ALTER TABLE SPRING_SESSION DROP COLUMN PRIMARY_ID;

这样改完,Spring Session的默认插入逻辑就能正常跑起来,不用额外配置。

最后验证下

不管用哪个方案,重启应用后试试创建会话(比如登录),看看SPRING_SESSION表能不能正常插入数据,要是没再报NULL错误,那就搞定啦!

内容的提问来源于stack exchange,提问作者Chetan

火山引擎 最新活动